1 Steps for Running NGSadmix

1.2 Run NGSadmix at Farm

# run k=2-5 (run_NGSadmix.sh)
for i in {2..5} 
do 
NGSadmix -likes /home/ktist/ph/data/new_vcf/MD7000/beagle/PH_maf05_pruned.BEAGLE.PL.gz -K $i -o /home/ktist/ph/data/NGSadmix/Ph_pruned_maf05_k$i -P 8 
done 

1.3 Run evalAdmix (locally)

#evalAdmix_runlocal.sh
evalAdmix -beagle Data/ngsadmix/PH_maf05_pruned_BEAGLE.PL.gz -fname Data/ngsadmix/PH_pruned_maf05_k2.fopt.gz -qname Data/ngsadmix/PH_pruned_maf05_k2.qopt -P 8 -o output.corres.k2.txt

2 Results from NGSadmix

#Output files
qfiles<-list.files("../Data/ngsadmix/",pattern=".qopt")

ofiles<-list.files("../Data/ngsadmix/",pattern="output.corres")

#population info
pop<-read.csv("../Data/Sample_metadata_892pops.csv")

pop$Population.Year<-factor(pop$Population.Year, levels=c("TB91","TB96","TB06","TB17","PWS91","PWS96","PWS07","PWS17","SS96","SS06","SS17","BC17","WA17","CA17"))

poporder<-paste(pop$Population.Year[order(pop$Population.Year)])
pop_order<-c("TB91","TB96","TB06","TB17","PWS91","PWS96","PWS07","PWS17","SS96","SS06","SS17","BC17","WA17","CA17")

#color for populations
#levels=c("TB","PWS","SS", "BC","WA","CA"))
#colors= cols ("#56b4e9" "#cc79a7" "#009e73" "#0072b2" "#d55e00" "#e69f00" "#f0e442")

for (i in 1:length(qfiles)){
    # extract K from the file name
    oname<-ofiles[i]
    k<-as.integer(substr(oname, 16,17))
    
    #read the qopt file for k=k
    q<-read.table(paste0("../Data/ngsadmix/", qfiles[i]))
    
    #order according to population and plot the NGSadmix results
    q$id<-pop$Population.Year
    q<-q[order(q$id),]
    
    ord<-orderInds(pop = as.vector(poporder), q = q[,1:(i+1)])
    
    xlabels<-data.frame(x=tapply(1:length(poporder),list(poporder), mean))
    xlabels$pop<-factor(rownames(xlabels), levels=pop_order)
    xlabels<-xlabels[order(xlabels$pop),]
    
    # c('PWS color', 'TB color', 'CA color" )
    #if (i==1|i==2) colors=c(4,2,7)
    if (i==1|i==2) colors=c(2,4,7)
    #colors<-c("#cc79a7","#56b4e9", "#e69f00")
    #if (i==3) colors=c(5,4,7,2,3) 
    if (i==3) colors=c(5,2,7,4,3) 
    if (i==4) colors=c(4,2,5,7,3)

    {png(paste0("../Output/ngsadmix/Admix_plot_k",k,".png"), height = 3.5, width=8, unit="in", res=300)
    barplot(t(q[,1:(i+2)])[,ord],col=colors,space=0,border=NA,xaxt="n",xlab="Population",ylab=paste0("Admixture proportions for K=",k))
    text(xlabels$x,-0.05,xlabels$pop,xpd=T, srt=90, adj=1,cex=0.8)
    abline(v=cumsum(sapply(unique(poporder[ord]),function(x){sum(pop[ord,"Population.Year"]==x)})),col=1,lwd=1.2)
    dev.off()}
    
    #Plot the correlation matrix from evalAdmix
    r<-read.table(paste0("../Data/ngsadmix/",ofiles[i]))
    
    # Plot correlation of residuals
    {pdf(paste0("../Output/ngsadmix/evalAdmix_corplot_k",k,".pdf"), height = 8, width=10)
    plotCorRes(cor_mat = r, pop = as.vector(pop[,"Population.Year"]), ord = ord, title=paste0("Evaluation of admixture proportions with K=",k), max_z=0.1, min_z=-0.1)
    dev.off()}
}

  • Correlation of residuals


3 Use Clumpak to choose the best K

3.1 Run NGSadmix 10 times for each K (K= 3 & 4)

  • see RunNGSadmix.sh

3.2 Compile all likelihood numbers from log files into 1 (logfile)

#linux code (won't work for unix)
(for log in `ls *.log`; do grep -oP 'Ph_pruned_maf05_\K[^ ]+|like=\K[^ ]+' $log; done) > logfile_k3
(for log in `ls *.log`; do grep -oP 'Ph_pruned_maf05_\K[^ ]+|like=\K[^ ]+' $log; done) > logfile_k4

3.3 Read ‘logfile’ & create an input file for Clumpak

log2<-read.table("../Data/ngsadmix/logfile_k2", sep="\t", header =FALSE)
log3<-read.table("../Data/ngsadmix/logfile_k3", sep="\t", header =FALSE)
log4<-read.table("../Data/ngsadmix/logfile_k4", sep="\t", header =FALSE)
logk2<-log2[c(FALSE,TRUE),]
logk3<-log3[c(FALSE,TRUE),]
logk4<-log4[c(FALSE,TRUE),]

logs<-data.frame(K=c(rep(2, times=10),rep(3, times=10), rep(4, times=10)), Liklihood=c(logk2,logk3, logk4))
write.table(logs, "../Output/ngsadmix/logs.txt", sep="\t", row.names = F, col.names = F, quote=F)
# DO NOT use special character in the file name
#Must have at least three K values

#upload the logs.txt to Clumpak website
# http://clumpak.tau.ac.il

#'Estimating the Best K (from Clumpak)'

# The method of Evanno enables the user to identify a single k value, out of a range of K values, which captures the uppermost 
# level of structure. This method was purposed by Evonno et al. in 2005 (Molecular Ecology 14, 2005). In addition, we also use
# ln(Pr(X|K) #values in order to identify the k for which Pr(K=k) is highest (as described in STRUCTURE's manual, section 5.1).

#STRUCTURE manual
#' it is not infrequent that in real data the value of our model choice criterion continues to increase with increasing K. 
# Then it usually makes sense to focus on values of K that capture most of the structure in the data and that seem 
# biologically sensible.'

# plot admix values
  • Resuls from CLUMPAK
    “Optimal K by Evanno is: 3”

4 Run Population specific NGSadmix & FSTruct

4.1 PWS

  • Create bash scritpts to to prep the files
#Create beagle files (create_beagle.sh)
#pops<-c("PWS91","PWS96","PWS07","PWS17")
sink(paste0("../Data/Slurmscripts/beagle_pws.sh"))
cat("#!/bin/bash -l\n\n")
cat(paste0("#SBATCH --job-name=beagle \n"))
cat(paste0("#SBATCH --mem=16G \n")) 
cat(paste0("#SBATCH --ntasks=8 \n"))
cat(paste0("#SBATCH -e beagle.err  \n"))
cat(paste0("#SBATCH --time=72:00:00  \n"))
cat(paste0("#SBATCH -p high  \n"))
cat("\n")
for (i in 1:26){
   cat(paste0("vcftools --gzvcf /home/ktist/ph/data/new_vcf/MD7000/pruned/pruned_PWSonly_maf05_50.5.5.vcf.gz --chr chr1 --out /home/ktist/ph/data/new_vcf/MD7000/beagle/PWSonly_pruned_c",i," --BEAGLE-PL \n"))
}

for (i in 2:26){
    cat(paste0("sed -e '1, 1d' < /home/ktist/ph/data/new_vcf/MD7000/beagle/PWSonly_pruned_c",i,".BEAGLE.PL > /home/ktist/ph/data/new_vcf/MD7000/beagle/PWSonly_pruned_c",i,".2.BEAGLE.PL \n"))
}
cat("\n")

cat("cat /home/ktist/ph/data/new_vcf/MD7000/beagle/PWSonly_pruned_c1.BEAGLE.PL ") 
for (i in 2:26){
    cat(paste0("/home/ktist/ph/data/new_vcf/MD7000/beagle/PWSonly_pruned_c",i,".2.BEAGLE.PL "))
}
cat(paste0(" > /home/ktist/ph/data/new_vcf/MD7000/beagle/PWSonly_pruned_BEAGLE.PL \n"))
cat("gzip /home/ktist/ph/data/new_vcf/MD7000/beagle/PWSonly_pruned_BEAGLE.PL \n\n")

sink(NULL)

4.1.1 Run NGSadmix at Farm

#create slurm scripts to run NGSadmix
# run k=2-5 (run_NGSadmix.sh)
#first run once:
for (i in 2:6) {
    sink(paste0("../Data/Slurmscripts/RunNGSadmix.",i,".sh"))
    cat("#!/bin/bash -l\n\n")
    cat(paste0("#SBATCH --job-name=admix.",i,"\n"))
    cat("#SBATCH --mem=16G
#SBATCH --ntasks=8 \n")
    cat(paste0("#SBATCH --error admix.",i,".err\n"))
    cat("#SBATCH --time=48:00:00
#SBATCH --mail-user=ktist@ucdavis.edu ##email you when job starts,ends,etc
#SBATCH --mail-type=ALL
#SBATCH -p high \n")
    cat("\n")
    cat("module load angsd\n\n")
    
    cat(paste0("NGSadmix -likes /home/ktist/ph/data/new_vcf/MD7000/beagle/PWSonly_pruned_BEAGLE.PL.gz -K ",i," -o /home/ktist/ph/data/NGSadmix/PWSonly_pruned_maf05_k",i," \n"))
    sink(NULL)
}

# Run 10 times for each K to feed into Clumpak

4.1.2 Run evalAdmix (locally)

sink(paste0("../Data/Slurmscripts/evalAdmix_runlocal_pws.sh"))
cat("#!/bin/bash \n\n")

#evalAdmix_runlocal_pws.sh
for (i in 2:6){
    cat(paste0("evalAdmix -beagle Data/ngsadmix/PWSonly_pruned_maf05_BEAGLE.PL.gz -fname Data/ngsadmix/PWSonly_pruned_maf05_k",i,".fopt.gz -qname Data/ngsadmix/PWSonly_pruned_maf05_k",i,".qopt -P 8 -o output.corres.k",i,".txt \n"))
}
sink(NULL)

4.1.3 NGSadmix and EvalAdmix outputs for PWS

#Output files
qfiles<-list.files("../Data/ngsadmix/",pattern="^PWSonly.+.qopt")
ofiles<-list.files("../Data/ngsadmix/",pattern="^PWSonly.+output.corres")

#population info
pop<-read.csv("../Data/Sample_metadata_892pops.csv")
ppop<-pop[grepl("PWS",pop$Sample),]
ppop$Population.Year<-factor(ppop$Population.Year, levels=c("PWS91","PWS96","PWS07","PWS17"))
poporder<-paste(ppop$Population.Year[order(ppop$Population.Year)])
pop_order<-c("PWS91","PWS96","PWS07","PWS17")

for (i in 1:length(qfiles)){
    # extract K from the file name
    oname<-ofiles[i]
    k<-as.integer(str_extract(oname, "[[:digit:]]+"))
    
    #read the qopt file for k=k
    q<-read.table(paste0("../Data/ngsadmix/", qfiles[i]))
    
    #order according to population and plot the NGSadmix results
    q$id<-ppop$Population.Year
    q<-q[order(q$id),]
    
    ord<-orderInds(pop = as.vector(poporder), q = q[,1:(i+1)])
    
    xlabels<-data.frame(x=tapply(1:length(poporder),list(poporder), mean))
    xlabels$pop<-factor(rownames(xlabels), levels=pop_order)
    xlabels<-xlabels[order(xlabels$pop),]
    
    # c('PWS color', 'TB color', 'CA color" )
    #if (i==1|i==2) colors=c(4,2,7)
    if (i==1|i==2) colors=c(2,4,7)
    #colors<-c("#cc79a7","#56b4e9", "#e69f00")
    #if (i==3) colors=c(5,4,7,2,3) 
    if (i==3) colors=c(5,2,7,4,3) 
    if (i==4) colors=c(4,2,5,7,3)

    {png(paste0("../Output/ngsadmix/PWSonly_Admix_plot_k",k,".png"), height = 3.5, width=8, unit="in", res=300)
    barplot(t(q[,1:(i+2)])[,ord],col=colors,space=0,border=NA,xaxt="n",xlab="Population",ylab=paste0("Admixture proportions for K=",k))
    text(xlabels$x,-0.05,xlabels$pop,xpd=T, srt=90, adj=1,cex=0.8)
    abline(v=cumsum(sapply(unique(poporder[ord]),function(x){sum(ppop[ord,"Population.Year"]==x)})),col=1,lwd=1.2)
    dev.off()}
    
    #Plot the correlation matrix from evalAdmix
    r<-read.table(paste0("../Data/ngsadmix/",ofiles[i]))
    
    # Plot correlation of residuals
    {pdf(paste0("../Output/ngsadmix/PWSonly_evalAdmix_corplot_k",k,".pdf"), height = 8, width=10)
    plotCorRes(cor_mat = r, pop = as.vector(ppop[,"Population.Year"]), ord = ord, title=paste0("Evaluation of admixture proportions with K=",k), max_z=0.1, min_z=-0.1)
    dev.off()}
}

4.1.4 Best K estimate

  • Run each k for 10 times to assess the best k
#create slurm scripts to run NGSadmix x 10
for (i in 2:6) {
    sink(paste0("../Data/Slurmscripts/NGSadmixP.",i,".sh"))
    cat("#!/bin/bash -l\n\n")
    cat(paste0("#SBATCH --job-name=admix.",i,"\n"))
    cat("#SBATCH --mem=16G
#SBATCH --ntasks=8 \n")
    cat(paste0("#SBATCH --error admix.",i,".err\n"))
    cat("#SBATCH --time=300:00:00
#SBATCH --mail-user=ktist@ucdavis.edu ##email you when job starts,ends,etc
#SBATCH --mail-type=ALL
#SBATCH -p high \n")
    cat("\n")
    cat("module load angsd\n\n")
    
    for (j in 1:10){
        cat(paste0("NGSadmix -likes /home/ktist/ph/data/new_vcf/MD7000/beagle/PWSonly_pruned_maf05_BEAGLE.PL.gz -K ",i," -o /home/ktist/ph/data/NGSadmix/PWSonly_pruned_maf05_k",i,"_run",j," \n"))
    }
    sink(NULL)
}
  • Compile all likelihood numbers from log files into 1 (logfile)
#linux code (won't work for unix)
(for log in `ls *.log`; do grep -oP 'PWSonly_pruned_maf05_\K[^ ]+|like=\K[^ ]+' $log; done) > logfile_k3
  • Slurmscripts to create log files
sink(paste0("../Data/Slurmscripts/logfilesP.sh"))
cat("#!/bin/bash -l\n\n")
cat(paste0("#SBATCH --job-name=logP \n"))
cat("#SBATCH --mem=16G
#SBATCH --ntasks=8 \n")
cat(paste0("#SBATCH --error logP.err\n"))
cat("#SBATCH --time=24:00:00
#SBATCH -p high \n")
cat("\n")
for (k in 2:6){
    cat(paste0("cd /home/ktist/ph/data/NGSadmix/PWS_k",k,"/ \n"))
    cat("(for log in `ls *.log`; do grep -oP 'like=\\K[^ ]+' $log; done) > pws_logfile_k")
    cat(paste0(k ," \n"))
}
sink(NULL)
#log2<-read.table("../Data/ngsadmix/PWS/pws_log_k2", sep="\t", header =FALSE)
#log3<-read.table("../Data/ngsadmix/PWS/pws_log_k3", sep="\t", header =FALSE)
#log4<-read.table("../Data/ngsadmix/PWS/pws_log_k4", sep="\t", header =FALSE)
#log5<-read.table("../Data/ngsadmix/PWS/pws_log_k5", sep="\t", header =FALSE)
#
#logk2<-log2[c(FALSE,FALSE,TRUE),]
#logk3<-log3[c(FALSE,FALSE,TRUE),]
#logk4<-log4[c(FALSE,FALSE,TRUE),]
#logk5<-log5[c(FALSE,FALSE,TRUE),]
log2<-read.table("../Data/ngsadmix/PWS/pws_logfile_k2", sep="\t", header =FALSE)
log3<-read.table("../Data/ngsadmix/PWS/pws_logfile_k3", sep="\t", header =FALSE)
log4<-read.table("../Data/ngsadmix/PWS/pws_logfile_k4", sep="\t", header =FALSE)
log5<-read.table("../Data/ngsadmix/PWS/pws_logfile_k5", sep="\t", header =FALSE)
log6<-read.table("../Data/ngsadmix/PWS/pws_logfile_k6", sep="\t", header =FALSE)

logs1<-data.frame(K=c(rep(2, times=10),rep(3, times=10), rep(4, times=10),rep(5, times=10)), Liklihood=c(log2$V1,log3$V1, log4$V1, log5$V1))

logs2<-data.frame(K=c(rep(2, times=4),rep(3, times=4), rep(4, times=4),rep(5, times=4),rep(6, times=4)), Liklihood=c(log2$V1[1:4],log3$V1[1:4], log4$V1[1:4], log5$V1[1:4],log6$V1[1:4]))


#logs<-data.frame(K=c(rep(2, times=10),rep(3, times=9)), Liklihood=c(logk2,logk3))
#logs<-data.frame(K=c(rep(2, times=5),rep(3, times=5), rep(4, times=5),rep(5, times=5)), Liklihood=c(logk2[1:5],logk3[1:5], logk4, logk5))
write.table(logs, "../Output/ngsadmix/PWSonly_logs.txt", sep="\t", row.names = F, col.names = F, quote=F)
write.table(logs1, "../Output/ngsadmix/PWSonly_logs1.txt", sep="\t", row.names = F, col.names = F, quote=F)
write.table(logs2, "../Output/ngsadmix/PWSonly_logs2.txt", sep="\t", row.names = F, col.names = F, quote=F)

# DO NOT use special character in the file name
#Must have at least three K values
  • CLUMPAK suggests K=3 as optimal by Evanno Method
  • However, k with the highest Prob(K=k) is: 6 (or max k) –not sure how to interpret, but stick to K=3

4.1.5 FSTruct

  • Run for all values for comparison
#all<-c("TB91","TB96","TB06","TB17","PWS91","PWS96","PWS07","PWS17","SS96","SS06","SS17","BC17","WA17","CA17")
pop_info<-read.csv("../Data/Sample_metadata_892pops.csv")
pws<-c("PWS91","PWS96","PWS07","PWS17")
pop_infoP<-pop_info[pop_info$pop=="PWS",]
cols6<-c('#fbb4ae','#b3cde3','#ccebc5','#decbe4','#fed9a6','#ffffcc')

wilcox<-list()
for (k in 2:6){
    qmat<-read.table(paste0("../Data/ngsadmix/PWSonly_pruned_maf05_k",k,".qopt"), header = F)
    qmat<-cbind(pop_infoP[,c("Sample","Population.Year")], qmat)
    colnames(qmat)[1:2]<-c("ind","pop")
    qmat$pop<-factor(qmat$pop, levels=pws)
    qmat<-qmat[order(qmat$pop),]
    
    kmeans<-apply(as.matrix(qmat[qmat$pop==pws[1],3:(k+2)]),2,mean)
    k_order<-names(kmeans[order(kmeans, decreasing = T)])
    qmat<-qmat[,c("ind","pop",k_order)]
    qmat_sorted<-data.frame()
    for (i in 1:length(pws)){
        df<-qmat[qmat$pop==pws[i],]
        df<-df[order(df[,colnames(df)[colnames(df)==k_order[1]]],df[,colnames(df)[colnames(df)==k_order[k]]],decreasing = c(TRUE,FALSE), method="radix"),]
        qmat_sorted<-rbind(qmat_sorted, df)
    }
    
    nind<-data.frame(pop=pws)
    nind$n[1]<-nrow(qmat[qmat$pop==pws[1],])
    nind$mid[1]<-nind$n[1]/2
    for(i in 2:length(pws)){
        no<-nrow(qmat[qmat$pop==pws[i],])
        nind$n[i]<-nind$n[i-1]+no
        nind$mid[i]<-nind$n[i-1]+no/2
    }

    qm<-qmat_sorted[,2:(k+2)]
    Q_plot(Q = qm,K=k)+
            ggplot2::scale_fill_manual(values=cols6)+
            ggplot2::scale_color_manual(values=cols6)+
            ggplot2::scale_x_continuous(labels=pws, breaks=nind$mid)+
            theme_minimal()+xlab('')+ylab('')+ylim(0,1)+
            theme(panel.grid=element_blank(), legend.position = "none", axis.text.x = element_text(size=8))+
            ggplot2::annotate('segment', x=nind$n[1:3]+0.5,y=rep(0, times=3),yend=rep(1, times=3), xend=nind$n[1:3]+0.5,     color="gray30", size=0.3)
    ggsave(paste0('../Output/ngsadmix/PWSonly_plot_k',k,'.png'), width = 8, height = 3.5, dpi=300)
           
    #calculate stats
    Qs<-list() #Qmatrix
    for (i in 1: length(pws)){
        df<-qmat[qmat$pop==pws[i],]
        Qs[[i]]<-df
        names(Qs)[i]<-pws[i]
    }        

    bootstrap <- Q_bootstrap(matrices = Qs,n_replicates = 100,K = k,seed = 1)
    #This does not save the plots...
    {png(paste0("../Output/ngsadmix/PWSonly_fstruct_stats_k",k,".png"), width=10, height=7, unit='in', res=300)
    cowplot::plot_grid(bootstrap$plot_boxplot + ggplot2::ggtitle("Box Plot")+ggplot2::scale_x_discrete(labels=pws), 
                           bootstrap$plot_violin + ggplot2::ggtitle("Violin Plot")+ggplot2::scale_x_discrete(labels=pws), 
                           bootstrap$plot_ecdf + ggplot2::ggtitle("ECDF Plot") +
                               ggplot2::scale_color_brewer(palette = "Dark2", labels=pws), nrow=2)
    dev.off()}

    wilcox[[k]]<-bootstrap$test_pairwise_wilcox
}

4.1.6 FSTruct run for optimal K (K=3)

pop_info<-read.csv("../Data/Sample_metadata_892pops.csv")
pws<-c("PWS91","PWS96","PWS07","PWS17")
pop_infoP<-pop_info[pop_info$pop=="PWS",]
cols6<-c('#fbb4ae','#b3cde3','#ccebc5','#decbe4','#fed9a6','#ffffcc')
cols3<-c('#8dd3c7','#ffffb3','#bebada')


qmat<-read.table(paste0("../Data/ngsadmix/PWSonly_pruned_maf05_k3.qopt"), header = F)
qmat<-cbind(pop_infoP[,c("Sample","Population.Year")], qmat)
colnames(qmat)[1:2]<-c("ind","pop")
qmat$pop<-factor(qmat$pop, levels=pws)
qmat<-qmat[order(qmat$pop),]

kmeans<-apply(as.matrix(qmat[qmat$pop==pws[1],3:5]),2,mean)
k_order<-names(kmeans[order(kmeans, decreasing = T)])
qmat<-qmat[,c("ind","pop",k_order)]
qmat_sorted<-data.frame()
for (i in 1:length(pws)){
        df<-qmat[qmat$pop==pws[i],]
        df<-df[order(df[,colnames(df)[colnames(df)==k_order[1]]],df[,colnames(df)[colnames(df)==k_order[3]]],decreasing = c(TRUE,FALSE), method="radix"),]
        qmat_sorted<-rbind(qmat_sorted, df)
}
    
for (i in 1:length(pws)){
        df<-qmat[qmat$pop==pws[i],]
        df<-df[order(df[,colnames(df)[colnames(df)==k_order[2]]],decreasing = c(TRUE), method="radix"),]
        qmat_sorted<-rbind(qmat_sorted, df)
}
nind<-data.frame(pop=pws)
nind$n[1]<-nrow(qmat[qmat$pop==pws[1],])
nind$mid[1]<-nind$n[1]/2
for(i in 2:length(pws)){
    no<-nrow(qmat[qmat$pop==pws[i],])
    nind$n[i]<-nind$n[i-1]+no
    nind$mid[i]<-nind$n[i-1]+no/2
}

Q_plot(Q = qmat_sorted,K=3)+
        ggplot2::scale_fill_manual(values=cols3)+
        ggplot2::scale_color_manual(values=cols3)+
        ggplot2::scale_x_continuous(labels=pws, breaks=nind$mid)+
        theme_minimal()+xlab('')+ylab('')+
        theme(panel.grid=element_blank(), legend.position = "none", axis.text.x = element_text(size=8))+
        ggplot2::annotate('segment', x=nind$n[1:3]+0.5,y=rep(0, times=3),yend=rep(1, times=3), xend=nind$n[1:3]+0.5,     color="gray30", size=0.3)
ggsave(paste0('../Output/ngsadmix/PWSonly_OptimalK3.png'), width = 8, height = 3.5, dpi=300)
           
#calculate stats
Qs<-list() #Qmatrix
for (i in 1: length(pws)){
    df<-qmat[qmat$pop==pws[i],]
    Qs[[i]]<-df
    names(Qs)[i]<-pws[i]
}        
bootstrap <- Q_bootstrap(matrices = Qs,n_replicates = 100,K = 3,seed = 1)
#This does not save the plots...
{png(paste0("../Output/ngsadmix/PWSonly_fstruct_stats_OptK3.png"), width=10, height=7, unit='in', res=300)
cowplot::plot_grid(bootstrap$plot_boxplot + ggplot2::ggtitle("Box Plot")+ggplot2::scale_x_discrete(labels=pws), 
                       bootstrap$plot_violin + ggplot2::ggtitle("Violin Plot")+ggplot2::scale_x_discrete(labels=pws), 
                       bootstrap$plot_ecdf + ggplot2::ggtitle("ECDF Plot") +
                               ggplot2::scale_color_brewer(palette = "Dark2", labels=pws), nrow=2)
dev.off()}

bootstrap$test_pairwise_wilcox

#      PWS91   PWS96   PWS07  
#PWS96 < 2e-16 -       -      
#PWS07 < 2e-16 0.13    -      
#PWS17 3.6e-07 1.0e-14 < 2e-16
#
#P value adjustment method: holm 

bootstrap$test_kruskal_wallis
#data:  all_stats$ratio by all_stats$Matrix
#Kruskal-Wallis chi-squared = 209.18, df = 3, p-value < 2.2e-16


PWS_k3_statistics<-bootstrap$statistics

{png(paste0(“Output/ngsadmix/PWSonly_fstruct_stats_OptK3.png”), width=10, height=7, unit=‘in’, res=300) cowplot::plot_grid(bootstrap\(plot_boxplot + ggplot2::ggtitle("Box Plot")+ggplot2::scale_x_discrete(labels=pws), bootstrap\)plot_violin + ggplot2::ggtitle(“Violin Plot”)+ggplot2::scale_x_discrete(labels=pws), bootstrap$plot_ecdf + ggplot2::ggtitle(“ECDF Plot”) + ggplot2::scale_color_brewer(palette = “Dark2”, labels=pws), nrow=2) dev.off()}


4.2 TB

#first create ped/bed files with adding variant id
module load plink
plink --vcf /home/ktist/ph/data/new_vcf/MD7000/TBonly_NS0.5_maf05.vcf.gz --set-missing-var-ids @:#[ph]\\$r,\\$a --make-bed --out /home/ktist/ph/data/new_vcf/MD7000/plinkfiles/TBonly_NS0.5_maf05

plink --bfile /home/ktist/ph/data/new_vcf/MD7000/plinkfiles/TBonly_NS0.5_maf05 --recode --tab --out /home/ktist/ph/data/new_vcf/MD7000/plinkfiles/TBonly_NS0.5_maf05

#find highly correlated sites for pruning
plink --file /home/ktist/ph/data/new_vcf/MD7000/plinkfiles/TBonly_NS0.5_maf05 --indep-pairwise 50'kb' 5 0.5 --out /home/ktist/ph/data/new_vcf/MD7000/plinkfiles/TBonly_NS0.5_maf05_50_5_0.5

#Reformat prun.in file with running the reformat_prunin.R
R
source("reformat_prunin.R")
reformat_prunin("ph/data/new_vcf/MD7000/plinkfiles/TBonly_NS0.5_maf05_50_5_0.5.prune.in")
quit()

## Use bcftools to subset the VCF file with .prune.in.sites.txt
bcftools index /home/ktist/ph/data/new_vcf/MD7000/TBonly_NS0.5_maf05.vcf.gz 

bcftools view -R /home/ktist/ph/data/new_vcf/MD7000/plinkfiles/TBonly_NS0.5_maf05_50_5_0.5.prune.in.sites.txt  /home/ktist/ph/data/new_vcf/MD7000/TBonly_NS0.5_maf05.vcf.gz > /home/ktist/ph/data/new_vcf/MD7000/pruned/TBonly_NS0.5_maf05_pruned.vcf

bgzip /home/ktist/ph/data/new_vcf/MD7000/pruned/TBonly_NS0.5_maf05_pruned.vcf
## Create beagle files
sink(paste0("../Data/Slurmscripts/beagle_tb.sh"))
cat("#!/bin/bash -l\n\n")
cat(paste0("#SBATCH --job-name=beagle \n"))
cat(paste0("#SBATCH --mem=16G \n")) 
cat(paste0("#SBATCH --ntasks=8 \n"))
cat(paste0("#SBATCH -e beagle.err  \n"))
cat(paste0("#SBATCH --time=72:00:00  \n"))
cat(paste0("#SBATCH -p high  \n"))
cat("\n")
for (i in 1:26){
   cat(paste0("vcftools --gzvcf /home/ktist/ph/data/new_vcf/MD7000/pruned/TBonly_NS0.5_maf05_pruned.vcf.gz --chr chr1 --out /home/ktist/ph/data/new_vcf/MD7000/beagle/TBonly_pruned_c",i," --BEAGLE-PL \n"))
}
cat("\n")
for (i in 2:26){
    cat(paste0("sed -e '1, 1d' < /home/ktist/ph/data/new_vcf/MD7000/beagle/TBonly_pruned_c",i,".BEAGLE.PL > /home/ktist/ph/data/new_vcf/MD7000/beagle/TBonly_pruned_c",i,".2.BEAGLE.PL \n"))
}
cat("\n")

cat("cat /home/ktist/ph/data/new_vcf/MD7000/beagle/TBonly_pruned_c1.BEAGLE.PL ") 
for (i in 2:26){
    cat(paste0("/home/ktist/ph/data/new_vcf/MD7000/beagle/TBonly_pruned_c",i,".2.BEAGLE.PL "))
}
cat(paste0(" > /home/ktist/ph/data/new_vcf/MD7000/beagle/TBonly_pruned_BEAGLE.PL \n"))
cat("gzip /home/ktist/ph/data/new_vcf/MD7000/beagle/TBonly_pruned_BEAGLE.PL \n\n")

sink(NULL)

#first run once:
for (i in 2:6) {
    sink(paste0("../Data/Slurmscripts/RunNGSadmix",i,".sh"))
    cat("#!/bin/bash -l\n\n")
    cat(paste0("#SBATCH --job-name=admix",i,"\n"))
    cat("#SBATCH --mem=16G
#SBATCH --ntasks=8 \n")
    cat(paste0("#SBATCH --error admix",i,".err\n"))
    cat("#SBATCH --time=48:00:00
#SBATCH --mail-user=ktist@ucdavis.edu ##email you when job starts,ends,etc
#SBATCH --mail-type=ALL
#SBATCH -p high \n")
    cat("\n")
    cat("module load angsd\n\n")
    
    cat(paste0("NGSadmix -likes /home/ktist/ph/data/new_vcf/MD7000/beagle/TBonly_pruned_BEAGLE.PL.gz -K ",i," -o /home/ktist/ph/data/NGSadmix/PWSonly_pruned_maf05_k",i," \n"))
    sink(NULL)
}

4.2.1 Run evalAdmix for TB (locally)

sink(paste0("../Data/Slurmscripts/evalAdmix_runlocal_tb.sh"))
cat("#!/bin/bash \n\n")
for (i in 2:6){
    cat(paste0("evalAdmix -beagle Data/ngsadmix/TB/TBonly_pruned_maf05_BEAGLE.PL.gz -fname Data/ngsadmix/TB/TBonly_pruned_maf05_k",i,".fopt.gz -qname Data/ngsadmix/TB/TBonly_pruned_maf05_k",i,".qopt -P 8 -o TBonly.output.corres.k",i,".txt \n"))
}
sink(NULL)

4.2.2 NGSadmix and EvalAdmix outputs for TB

#Output files
qfiles<-list.files("../Data/ngsadmix/TB/",pattern="^TBonly.+.qopt")
ofiles<-list.files("../Data/ngsadmix/TB/",pattern="^TBonly.+output.corres")

#population info
pop<-read.csv("../Data/Sample_metadata_892pops.csv")
tpop<-pop[grepl("TB",pop$Sample),]
tpop$Population.Year<-factor(tpop$Population.Year, levels=c("TB91","TB96","TB06","TB17"))
tpoporder<-paste(tpop$Population.Year[order(tpop$Population.Year)])
tpop_order<-c("TB91","TB96","TB06","TB17")

for (i in 1:length(qfiles)){
    # extract K from the file name
    oname<-ofiles[i]
    k<-as.integer(str_extract(oname, "[[:digit:]]+"))
    
    #read the qopt file for k=k
    q<-read.table(paste0("../Data/ngsadmix/TB/", qfiles[i]))
    
    #order according to population and plot the NGSadmix results
    q$id<-tpop$Population.Year
    q<-q[order(q$id),]
    
    ord<-orderInds(pop = as.vector(tpoporder), q = q[,1:(i+1)])
    
    xlabels<-data.frame(x=tapply(1:length(tpoporder),list(tpoporder), mean))
    xlabels$pop<-factor(rownames(xlabels), levels=tpop_order)
    xlabels<-xlabels[order(xlabels$pop),]
    
    # c('PWS color', 'TB color', 'CA color" )
    #if (i==1|i==2) colors=c(4,2,7)
    if (i==1|i==2) colors=c(2,4,7)
    #colors<-c("#cc79a7","#56b4e9", "#e69f00")
    #if (i==3) colors=c(5,4,7,2,3) 
    if (i==3) colors=c(5,2,7,4,3) 
    if (i==4) colors=c(4,2,5,7,3)

    {png(paste0("../Output/ngsadmix/TBonly_Admix_plot_k",k,".png"), height = 3.5, width=8, unit="in", res=300)
    barplot(t(q[,1:(i+2)])[,ord],col=colors,space=0,border=NA,xaxt="n",xlab="Population",ylab=paste0("Admixture proportions for K=",k))
    text(xlabels$x,-0.05,xlabels$pop,xpd=T, srt=90, adj=1,cex=0.8)
    abline(v=cumsum(sapply(unique(tpoporder[ord]),function(x){sum(tpop[ord,"Population.Year"]==x)})),col=1,lwd=1.2)
    dev.off()}
    
    #Plot the correlation matrix from evalAdmix
    r<-read.table(paste0("../Data/ngsadmix/TB/",ofiles[i]))
    
    # Plot correlation of residuals
    {pdf(paste0("../Output/ngsadmix/TBonly_evalAdmix_corplot_k",k,".pdf"), height = 8, width=10)
    plotCorRes(cor_mat = r, pop = as.vector(tpop[,"Population.Year"]), ord = ord, title=paste0("Evaluation of admixture proportions with K=",k), max_z=0.1, min_z=-0.1)
    dev.off()}
}

4.2.3 Run each k for 5 times to assess the best k (TB)

#create slurm scripts to run NGSadmix x 10
for (i in 2:6) {
    sink(paste0("../Data/Slurmscripts/NGSadmixT.",i,".sh"))
    cat("#!/bin/bash -l\n\n")
    cat(paste0("#SBATCH --job-name=admixT.",i,"\n"))
    cat("#SBATCH --mem=16G
#SBATCH --ntasks=8 \n")
    cat(paste0("#SBATCH --error admixT.",i,".err\n"))
    cat("#SBATCH --time=300:00:00
#SBATCH --mail-user=ktist@ucdavis.edu ##email you when job starts,ends,etc
#SBATCH --mail-type=ALL
#SBATCH -p high \n")
    cat("\n")
    cat("module load angsd\n\n")
    
    for (j in 1:5){
        cat(paste0("NGSadmix -likes /home/ktist/ph/data/new_vcf/MD7000/beagle/TBonly_pruned_maf05_BEAGLE.PL.gz -K ",i," -o /home/ktist/ph/data/NGSadmix/TBonly_pruned_maf05_k",i,"_run",j," \n"))
    }
    sink(NULL)
}
  • Compile all likelihood numbers from log files into 1 (logfile)
#linux code (won't work for unix)
(for log in `ls *.log`; do grep -oP 'like=\K[^ ]+' $log; done) > logfile_k3
sink(paste0("../Data/Slurmscripts/logfilesP.sh"))
cat("#!/bin/bash -l\n\n")
cat(paste0("#SBATCH --job-name=logP \n"))
cat("#SBATCH --mem=16G
#SBATCH --ntasks=8 \n")
cat(paste0("#SBATCH --error logP.err\n"))
cat("#SBATCH --time=24:00:00
#SBATCH -p high \n")
cat("\n")
for (k in 2:6){
    cat(paste0("cd /home/ktist/ph/data/NGSadmix/PWS_k",k,"/ \n"))
    cat("(for log in `ls *.log`; do grep -oP 'like=\\K[^ ]+' $log; done) > logfile_k")
    cat(paste0(k ," \n"))
}
sink(NULL)
log2<-read.table("../Data/ngsadmix/TB/tb_log_k2", sep="\t", header =FALSE)
log3<-read.table("../Data/ngsadmix/TB/tb_log_k3", sep="\t", header =FALSE)
log4<-read.table("../Data/ngsadmix/TB/tb_log_k4", sep="\t", header =FALSE)
log5<-read.table("../Data/ngsadmix/TB/tb_log_k5", sep="\t", header =FALSE)
log6<-read.table("../Data/ngsadmix/TB/tb_log_k6", sep="\t", header =FALSE)

#logs<-data.frame(K=c(rep(2, times=5),rep(3, times=5), rep(4, times=5),rep(5, times=5)), Liklihood=c(logk2[1:5],logk3[1:5], logk4, logk5))

logs<-data.frame(K=c(rep(2, times=3),rep(3, times=3), rep(4, times=3),rep(5, times=3),rep(6, times=3)), Liklihood=c(log2$V1[1:3],log3$V1[1:3], log4$V1[1:3], log5$V1,log6$V1))
write.table(logs, "../Output/ngsadmix/TBonly_logs.txt", sep="\t", row.names = F, col.names = F, quote=F)

# DO NOT use special character in the file name
#Must have at least three K values
  • k=3 is best by Evanno

4.2.4 FSTruct for TB only

pop_info<-read.csv("../Data/Sample_metadata_892pops.csv")
tb<-c("TB91","TB96","TB06","TB17")
pop_infoT<-pop_info[pop_info$pop=="TB",]

qmat<-read.table(paste0("../Data/ngsadmix/TB/TBonly_pruned_maf05_k3.qopt"), header = F)
qmat<-cbind(pop_infoT[,c("Sample","Population.Year")], qmat)
colnames(qmat)[1:2]<-c("ind","pop")
qmat$pop<-factor(qmat$pop, levels=tb)
qmat<-qmat[order(qmat$pop),]

kmeans<-apply(as.matrix(qmat[qmat$pop==tb[1],3:5]),2,mean)
k_order<-names(kmeans[order(kmeans, decreasing = T)])
qmat<-qmat[,c("ind","pop",k_order)]
qmat_sorted<-data.frame()
for (i in 1:length(tb)){
    df<-qmat[qmat$pop==tb[i],]
    df<-df[order(df[,colnames(df)[colnames(df)==k_order[1]]],df[,colnames(df)[colnames(df)==k_order[3]]],decreasing = c(TRUE,FALSE), method="radix"),]
    qmat_sorted<-rbind(qmat_sorted, df)
}
    
nind<-data.frame(pop=tb)
nind$n[1]<-nrow(qmat[qmat$pop==tb[1],])
nind$mid[1]<-nind$n[1]/2
for(i in 2:length(tb)){
    no<-nrow(qmat[qmat$pop==tb[i],])
    nind$n[i]<-nind$n[i-1]+no
    nind$mid[i]<-nind$n[i-1]+no/2
}

qm<-qmat_sorted[,2:4]
Q_plot(Q = qmat_sorted,K=3)+
            ggplot2::scale_fill_manual(values=cols3)+
            ggplot2::scale_color_manual(values=cols3)+
            ggplot2::scale_x_continuous(labels=tb, breaks=nind$mid)+
            theme_minimal()+xlab('')+ylab('')+
            theme(panel.grid=element_blank(), legend.position = "none", axis.text.x = element_text(size=8))+
            ggplot2::annotate('segment', x=nind$n[1:3]+0.5,y=rep(0, times=3),yend=rep(1, times=3), xend=nind$n[1:3]+0.5,     color="gray30", size=0.3)
ggsave(paste0('../Output/ngsadmix/TBonly_plot_Optimal.K3.png'), width = 8.2, height = 3.5, dpi=300)
       
#calculate stats
    Qs<-list() #Qmatrix
    for (i in 1: length(tb)){
        df<-qmat[qmat$pop==tb[i],]
        Qs[[i]]<-df
        names(Qs)[i]<-tb[i]
    }        

bootstrap <- Q_bootstrap(matrices = Qs,n_replicates = 100,K = 3,seed = 1)
cowplot::plot_grid(bootstrap$plot_boxplot + ggplot2::ggtitle("Box Plot")+ggplot2::scale_x_discrete(labels=tb), 
                       bootstrap$plot_violin + ggplot2::ggtitle("Violin Plot")+ggplot2::scale_x_discrete(labels=tb), 
                       bootstrap$plot_ecdf + ggplot2::ggtitle("ECDF Plot") +
                           ggplot2::scale_color_brewer(palette = "Dark2", labels=tb), nrow=2)
ggsave(paste0("../Output/ngsadmix/TBonly_fstruct_stats_OPTIAML.k3.png"), width=10, height=7, dpi=300)

bootstrap$test_pairwise_wilcox
#     TB91   TB96   TB06  
#TB96 1e-06  -      -     
#TB06 <2e-16 <2e-16 -     
#TB17 <2e-16 <2e-16 <2e-16

4.3 Run NGSadmix for SS

#first create ped/bed files with adding variant id
module load plink
plink --vcf /home/ktist/ph/data/new_vcf/MD7000/SSonly_NS0.5_maf05.vcf.gz --set-missing-var-ids @:#[ph]\\$r,\\$a --make-bed --out /home/ktist/ph/data/new_vcf/MD7000/plinkfiles/SSonly_NS0.5_maf05

plink --bfile /home/ktist/ph/data/new_vcf/MD7000/plinkfiles/SSonly_NS0.5_maf05 --recode --tab --out /home/ktist/ph/data/new_vcf/MD7000/plinkfiles/SSonly_NS0.5_maf05

#find highly correlated sites for pruning
plink --file /home/ktist/ph/data/new_vcf/MD7000/plinkfiles/SSonly_NS0.5_maf05 --indep-pairwise 50'kb' 5 0.5 --out /home/ktist/ph/data/new_vcf/MD7000/plinkfiles/SSonly_NS0.5_maf05_50_5_0.5

#Reformat prun.in file with running the reformat_prunin.R
R
source("reformat_prunin.R")
reformat_prunin("ph/data/new_vcf/MD7000/plinkfiles/SSonly_NS0.5_maf05_50_5_0.5.prune.in")
quit()

## Use bcftools to subset the VCF file with .prune.in.sites.txt
bcftools index /home/ktist/ph/data/new_vcf/MD7000/SSonly_NS0.5_maf05.vcf.gz 

bcftools view -R /home/ktist/ph/data/new_vcf/MD7000/plinkfiles/SSonly_NS0.5_maf05_50_5_0.5.prune.in.sites.txt  /home/ktist/ph/data/new_vcf/MD7000/SSonly_NS0.5_maf05.vcf.gz > /home/ktist/ph/data/new_vcf/MD7000/pruned/SSonly_NS0.5_maf05_pruned.vcf

bgzip /home/ktist/ph/data/new_vcf/MD7000/pruned/SSonly_NS0.5_maf05_pruned.vcf
## Create beagle files
sink(paste0("../Data/Slurmscripts/beagle_ss.sh"))
cat("#!/bin/bash -l\n\n")
cat(paste0("#SBATCH --job-name=beagle \n"))
cat(paste0("#SBATCH --mem=16G \n")) 
cat(paste0("#SBATCH --ntasks=8 \n"))
cat(paste0("#SBATCH -e beagle.err  \n"))
cat(paste0("#SBATCH --time=72:00:00  \n"))
cat(paste0("#SBATCH -p high  \n"))
cat("\n")
for (i in 1:26){
   cat(paste0("vcftools --gzvcf /home/ktist/ph/data/new_vcf/MD7000/pruned/SSonly_NS0.5_maf05_pruned.vcf.gz --chr chr1 --out /home/ktist/ph/data/new_vcf/MD7000/beagle/SSonly_pruned_c",i," --BEAGLE-PL \n"))
}
cat("\n")
for (i in 2:26){
    cat(paste0("sed -e '1, 1d' < /home/ktist/ph/data/new_vcf/MD7000/beagle/SSonly_pruned_c",i,".BEAGLE.PL > /home/ktist/ph/data/new_vcf/MD7000/beagle/SSonly_pruned_c",i,".2.BEAGLE.PL \n"))
}
cat("\n")

cat("cat /home/ktist/ph/data/new_vcf/MD7000/beagle/SSonly_pruned_c1.BEAGLE.PL ") 
for (i in 2:26){
    cat(paste0("/home/ktist/ph/data/new_vcf/MD7000/beagle/SSonly_pruned_c",i,".2.BEAGLE.PL "))
}
cat(paste0(" > /home/ktist/ph/data/new_vcf/MD7000/beagle/SSonly_pruned_maf05_BEAGLE.PL \n"))
cat("gzip /home/ktist/ph/data/new_vcf/MD7000/beagle/SSonly_pruned_maf05_BEAGLE.PL \n\n")

sink(NULL)

#first run once:
for (i in 2:6) {
    sink(paste0("../Data/Slurmscripts/RunNGSadmixS",i,".sh"))
    cat("#!/bin/bash -l\n\n")
    cat(paste0("#SBATCH --job-name=admixS",i,"\n"))
    cat("#SBATCH --mem=16G
#SBATCH --ntasks=8 \n")
    cat(paste0("#SBATCH --error admixS",i,".err\n"))
    cat("#SBATCH --time=48:00:00
#SBATCH --mail-user=ktist@ucdavis.edu ##email you when job starts,ends,etc
#SBATCH --mail-type=ALL
#SBATCH -p high \n")
    cat("\n")
    cat("module load angsd\n\n")
    
    cat(paste0("NGSadmix -likes /home/ktist/ph/data/new_vcf/MD7000/beagle/SSonly_pruned_maf05_BEAGLE.PL.gz -K ",i," -o /home/ktist/ph/data/NGSadmix/SSonly_pruned_maf05_k",i," \n"))
    sink(NULL)
}

4.4 Run evalAdmix for SS (locally)

sink(paste0("../Data/Slurmscripts/evalAdmix_runlocal_ss.sh"))
cat("#!/bin/bash \n\n")
for (i in 2:6){
    cat(paste0("evalAdmix -beagle Data/ngsadmix/SS/SSonly_pruned_maf05_BEAGLE.PL.gz -fname Data/ngsadmix/SS/SSonly_pruned_maf05_k",i,".fopt.gz -qname Data/ngsadmix/SS/SSonly_pruned_maf05_k",i,".qopt -P 8 -o SSonly_output.corres.k",i,".txt \n"))
}
sink(NULL)

4.5 NGSadmix and EvalAdmix outputs for SS

#Output files
qfiles<-list.files("../Data/ngsadmix/SS/",pattern="^SSonly.+.qopt")
ofiles<-list.files("../Data/ngsadmix/SS/",pattern="^SSonly.+output.corres")

#population info
pop<-read.csv("../Data/Sample_metadata_892pops.csv")
spop<-pop[grepl("SS",pop$Sample),]
spop$Population.Year<-factor(spop$Population.Year, levels=c("SS96","SS06","SS17"))
spoporder<-paste(spop$Population.Year[order(spop$Population.Year)])
spop_order<-c("SS96","SS06","SS17")

for (i in 1:length(qfiles)){
    # extract K from the file name
    oname<-qfiles[i]
    k<-as.integer(str_extract(oname, "[[:digit:]]+"))
    
    #read the qopt file for k=k
    q<-read.table(paste0("../Data/ngsadmix/SS/", qfiles[i]))
    
    #order according to population and plot the NGSadmix results
    q$id<-spop$Population.Year
    q<-q[order(q$id),]
    
    ord<-orderInds(pop = as.vector(spoporder), q = q[,1:(i+1)])
    
    xlabels<-data.frame(x=tapply(1:length(spoporder),list(spoporder), mean))
    xlabels$pop<-factor(rownames(xlabels), levels=spop_order)
    xlabels<-xlabels[order(xlabels$pop),]
    
    if (i==1|i==2) colors=c(2,4,7)
    if (i==3) colors=c(5,2,7,4,3) 
    if (i==4|i==5) colors=c(4,2,5,7,3)

    {png(paste0("../Output/ngsadmix/SSonly_Admix_plot_k",k,".png"), height = 3.5, width=6, unit="in", res=300)
    barplot(t(q[,1:(i+2)])[,ord],col=colors,space=0,border=NA,xaxt="n",xlab="Population",ylab=paste0("Admixture proportions for K=",k))
    text(xlabels$x,-0.05,xlabels$pop,xpd=T, srt=90, adj=1,cex=0.8)
    abline(v=cumsum(sapply(unique(spoporder[ord]),function(x){sum(spop[ord,"Population.Year"]==x)})),col=1,lwd=1.2)
    dev.off()}
    
    #Plot the correlation matrix from evalAdmix
    r<-read.table(paste0("../Data/ngsadmix/SS/",ofiles[i]))
    
    # Plot correlation of residuals
    {pdf(paste0("../Output/ngsadmix/SSonly_evalAdmix_corplot_k",k,".pdf"), height = 6, width=8)
    plotCorRes(cor_mat = r, pop = as.vector(spop[,"Population.Year"]), ord = ord, title=paste0("Evaluation of admixture proportions with K=",k), max_z=0.1, min_z=-0.1)
    dev.off()}
}


4.5.1 Run each k for 5 times to assess the best k (SS)

#create slurm scripts to run NGSadmix x 10
for (i in 2:5) {
    sink(paste0("../Data/Slurmscripts/NGSadmixS.",i,".sh"))
    cat("#!/bin/bash -l\n\n")
    cat(paste0("#SBATCH --job-name=admixS.",i,"\n"))
    cat("#SBATCH --mem=16G
#SBATCH --ntasks=8 \n")
    cat(paste0("#SBATCH --error admixS.",i,".err\n"))
    cat("#SBATCH --time=300:00:00
#SBATCH --mail-user=ktist@ucdavis.edu ##email you when job starts,ends,etc
#SBATCH --mail-type=ALL
#SBATCH -p high \n")
    cat("\n")
    cat("module load angsd\n\n")
    
    for (j in 1:5){
        cat(paste0("NGSadmix -likes /home/ktist/ph/data/new_vcf/MD7000/beagle/TBonly_pruned_maf05_BEAGLE.PL.gz -K ",i," -o /home/ktist/ph/data/NGSadmix/SSonly_pruned_maf05_k",i,"_run",j," \n"))
    }
    sink(NULL)
}

4.5.2 FSTruct for SS

pop_info<-read.csv("../Data/Sample_metadata_892pops.csv")
ss<-c("SS96","SS06","SS17")
pop_infoS<-pop_info[pop_info$pop=="SS",]

qmat<-read.table(paste0("../Data/ngsadmix/SS/SSonly_pruned_maf05_k3.qopt"), header = F)
qmat<-cbind(pop_infoS[,c("Sample","Population.Year")], qmat)
colnames(qmat)[1:2]<-c("ind","pop")
qmat$pop<-factor(qmat$pop, levels=ss)
qmat<-qmat[order(qmat$pop),]

kmeans<-apply(as.matrix(qmat[qmat$pop==ss[1],3:5]),2,mean)
k_order<-names(kmeans[order(kmeans, decreasing = T)])
qmat<-qmat[,c("ind","pop",k_order)]
qmat_sorted<-data.frame()
for (i in 1:length(ss)){
    df<-qmat[qmat$pop==ss[i],]
    df<-df[order(df[,colnames(df)[colnames(df)==k_order[1]]],df[,colnames(df)[colnames(df)==k_order[3]]],decreasing = c(TRUE,FALSE), method="radix"),]
    qmat_sorted<-rbind(qmat_sorted, df)
}
    
nind<-data.frame(pop=ss)
nind$n[1]<-nrow(qmat[qmat$pop==ss[1],])
nind$mid[1]<-nind$n[1]/2
for(i in 2:length(ss)){
    no<-nrow(qmat[qmat$pop==ss[i],])
    nind$n[i]<-nind$n[i-1]+no
    nind$mid[i]<-nind$n[i-1]+no/2
}

Q_plot(Q = qmat_sorted,K=3)+
            ggplot2::scale_fill_manual(values=cols3)+
            ggplot2::scale_color_manual(values=cols3)+
            ggplot2::scale_x_continuous(labels=ss, breaks=nind$mid)+
            theme_minimal()+xlab('')+ylab('')+
            theme(panel.grid=element_blank(), legend.position = "none", axis.text.x = element_text(size=8))+
            ggplot2::annotate('segment', x=nind$n[1:3]+0.5,y=rep(0, times=3),yend=rep(1, times=3), xend=nind$n[1:3]+0.5,     color="gray30", size=0.3)
ggsave(paste0('../Output/ngsadmix/SSonly_plot_Optimal.K3.png'), width = 8.2, height = 3.5, dpi=300)
       
#calculate stats
Qs<-list() #Qmatrix
for (i in 1: length(ss)){
    df<-qmat[qmat$pop==ss[i],]
    Qs[[i]]<-df
    names(Qs)[i]<-ss[i]
}        
bootstrap <- Q_bootstrap(matrices = Qs,n_replicates = 100,K = 3,seed = 1)
cowplot::plot_grid(bootstrap$plot_boxplot + ggplot2::ggtitle("Box Plot")+ggplot2::scale_x_discrete(labels=ss), 
                       bootstrap$plot_violin + ggplot2::ggtitle("Violin Plot")+ggplot2::scale_x_discrete(labels=ss), 
                       bootstrap$plot_ecdf + ggplot2::ggtitle("ECDF Plot") +
                           ggplot2::scale_color_brewer(palette = "Dark2", labels=ss), nrow=2)
ggsave(paste0("../Output/ngsadmix/SSonly_fstruct_stats_OPTIAML.k3.png"), width=10, height=7, dpi=300)

bootstrap$test_pairwise_wilcox
#     SS96    SS06   
#SS06 7.5e-07 -      
#SS17 0.15    8.4e-09

bootstrap$test_kruskal_wallis
#Kruskal-Wallis chi-squared = 42.173, df = 2, p-value = 6.955e-10

LS0tCnRpdGxlOiAiTkdTQWRtaXgiCm91dHB1dCI6IGh0bWxfbm90ZWJvb2sKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICAgIHRvYzogdHJ1ZSAKICAgICAgdG9jX2Zsb2F0OiB0cnVlCiAgICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgICB0aGVtZTogbHVtZW4KICAgICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgICAgZGZfcHJpbnQ6IHBhZ2VkCi0tLQoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0Kc291cmNlKCIuLi9Sc2NyaXB0cy9CYXNlU2NyaXB0cy5SIikKc291cmNlKCIuLi9Sc2NyaXB0cy92aXNGdW5zLlIiKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeSh0aWJibGUpCmxpYnJhcnkoY293cGxvdCkKbGlicmFyeShGU1RydWN0KQpgYGAKCgojIFN0ZXBzIGZvciBSdW5uaW5nIE5HU2FkbWl4IAoKIyMgUHJ1bmUgU05QczogVXNpbmcgUGxpbmsgdG8gcHJ1bmUgaGlnaGx5IGxpbmtlZCBzbnBzICAKCiogUGxpbmsgb3V0cHV0IGZpbGU6IFBIX21hZjA1X3BydW5lXzUwLjUuMC41LnBydW5lLmluCiAgICAtIE5lZWQgdG8gcmVmb3JtYXQgdGhlIHBsaW5rIG91dHB1dCAoeHh4LnBydW5lLmluKSBmaWxlIHRvIGEgYmVkIGZvcm1hdCBpbiBvcmRlciB0byBzdWJzZXQgYSB2Y2YgZmlsZSAgCmBgYHtiYXNoIGV2YWw9RkFMU0V9CiNSZWZvcm1hdCBwcnVuLmluIGZpbGUgd2l0aCBydW5uaW5nIHRoZSByZWZvcm1hdF9wcnVuaW4uUgpSCnNvdXJjZSgicmVmb3JtYXRfcHJ1bmluLlIiKQpyZWZvcm1hdF9wcnVuaW4oInBoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvcHJ1bmVkL1BIX21hZjA1X3BydW5lXzUwLjUuMC41LnBydW5lLmluIikKI291dHB1dCBwaC9kYXRhL25ld192Y2YvTUQ3MDAwL3BydW5lZC9QSF9tYWYwNV9wcnVuZV81MC41LjAuNS5wcnVuZS5pbi5zaXRlcy50eHQKcXVpdCgpCgojIyBVc2UgYmNmdG9vbHMgdG8gc3Vic2V0IHRoZSBWQ0YgZmlsZSB3aXRoIC5wcnVuZS5pbi5zaXRlcy50eHQKYmNmdG9vbHMgdmlldyAtUiAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL3BydW5lZC9QSF9tYWYwNV9wcnVuZV81MC41LjAuNS5wcnVuZS5pbi5zaXRlcy50eHQgIC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvUEhfRFA2MDBfNzAwMF9taW5RMjBfbWluTVEzMF9OUzAuNV9tYWYwNS52Y2YuZ3ogPiAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL3BydW5lZC9QSF9EUDYwMF83MDAwX05TMC41X21hZjA1X3BydW5lZC52Y2YKYmd6aXAgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9wcnVuZWQvUEhfRFA2MDBfNzAwMF9OUzAuNV9tYWYwNV9wcnVuZWQudmNmCgojQ3JlYXRlIGJlYWdsZSBmaWxlcyAoY3JlYXRlX2JlYWdsZS5zaCkKI2UuZy4gZG8gY2hyb21vc29tZSBieSBjaHJvbW9zb21lCnZjZnRvb2xzIC0tZ3p2Y2YgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9wcnVuZWQvUEhfRFA2MDBfNzAwMF9OUzAuNV9tYWYwNV9wcnVuZWQudmNmLmd6IC0tY2hyIGNocjEgLS1vdXQgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9iZWFnbGUvUEhfcHJ1bmVkX2MxIC0tQkVBR0xFLVBMIAoKIyByZW1vdmUgdGhlIGhlYWQgZnJvbSBjaHIyLTI2IChzbHVybSBzY3JpcHRzIGRvIG5vdCB3b3JrLCBzbyBydW4gdGhlIGNvbW1hbmQgb24gdGhlIHRlcm1pbmFsKSAoY29tYmluZWRfYmVhZ2xlLnNoKQpzZWQgLWUgJzEsIDFkJyA8IC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvYmVhZ2xlL1BIX3BydW5lZF9jMi5CRUFHTEUuUEwgID4gL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9iZWFnbGUvUEhfbm9oZWFkZXJfYzIuQkVBR0xFLlBMIAoKI0NvbWJpbmVkIGFsbCBpbnRvIG9uZSBmaWxlCmNhdCAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL2JlYWdsZS9QSF9wcnVuZWRfYzEuQkVBR0xFLlBMIC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvYmVhZ2xlL1BIX25vaGVhZGVyX2MyLkJFQUdMRS5QTCAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL2JlYWdsZS9QSF9ub2hlYWRlcl9jMy5CRUFHTEUuUEwgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9iZWFnbGUvUEhfbm9oZWFkZXJfYzQuQkVBR0xFLlBMIC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvYmVhZ2xlL1BIX25vaGVhZGVyX2M1LkJFQUdMRS5QTCAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL2JlYWdsZS9QSF9ub2hlYWRlcl9jNi5CRUFHTEUuUEwgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9iZWFnbGUvUEhfbm9oZWFkZXJfYzcuQkVBR0xFLlBMIC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvYmVhZ2xlL1BIX25vaGVhZGVyX2M4LkJFQUdMRS5QTCAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL2JlYWdsZS9QSF9ub2hlYWRlcl9jOS5CRUFHTEUuUEwgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9iZWFnbGUvUEhfbm9oZWFkZXJfYzEwLkJFQUdMRS5QTCAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL2JlYWdsZS9QSF9ub2hlYWRlcl9jMTEuQkVBR0xFLlBMIC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvYmVhZ2xlL1BIX25vaGVhZGVyX2MxMi5CRUFHTEUuUEwgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9iZWFnbGUvUEhfbm9oZWFkZXJfYzEzLkJFQUdMRS5QTCAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL2JlYWdsZS9QSF9ub2hlYWRlcl9jMTQuQkVBR0xFLlBMIC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvYmVhZ2xlL1BIX25vaGVhZGVyX2MxNS5CRUFHTEUuUEwgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9iZWFnbGUvUEhfbm9oZWFkZXJfYzE2LkJFQUdMRS5QTCAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL2JlYWdsZS9QSF9ub2hlYWRlcl9jMTcuQkVBR0xFLlBMIC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvYmVhZ2xlL1BIX25vaGVhZGVyX2MxOC5CRUFHTEUuUEwgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9iZWFnbGUvUEhfbm9oZWFkZXJfYzE5LkJFQUdMRS5QTCAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL2JlYWdsZS9QSF9ub2hlYWRlcl9jMjAuQkVBR0xFLlBMIC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvYmVhZ2xlL1BIX25vaGVhZGVyX2MyMS5CRUFHTEUuUEwgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9iZWFnbGUvUEhfbm9oZWFkZXJfYzIyLkJFQUdMRS5QTCAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL2JlYWdsZS9QSF9ub2hlYWRlcl9jMjMuQkVBR0xFLlBMIC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvYmVhZ2xlL1BIX25vaGVhZGVyX2MyNC5CRUFHTEUuUEwgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9iZWFnbGUvUEhfbm9oZWFkZXJfYzI1LkJFQUdMRS5QTCAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL2JlYWdsZS9QSF9ub2hlYWRlcl9jMjYuQkVBR0xFLlBMICA+IC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvYmVhZ2xlL1BIX21hZjA1X3BydW5lZF9CRUFHTEUuUEwgCgpiZ3ppcCAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL2JlYWdsZS9QSF9tYWYwNV9wcnVuZWRfQkVBR0xFLlBMIAoKYGBgCgojIyBSdW4gTkdTYWRtaXggYXQgRmFybSAKCmBgYHtiYXNoIGV2YWw9RkFMU0V9CiMgcnVuIGs9Mi01IChydW5fTkdTYWRtaXguc2gpCmZvciBpIGluIHsyLi41fSAKZG8gCk5HU2FkbWl4IC1saWtlcyAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL2JlYWdsZS9QSF9tYWYwNV9wcnVuZWQuQkVBR0xFLlBMLmd6IC1LICRpIC1vIC9ob21lL2t0aXN0L3BoL2RhdGEvTkdTYWRtaXgvUGhfcHJ1bmVkX21hZjA1X2skaSAtUCA4IApkb25lIApgYGAKCgojIyBSdW4gZXZhbEFkbWl4IChsb2NhbGx5KQpgYGB7YmFzaCBldmFsPUZBTFNFfQojZXZhbEFkbWl4X3J1bmxvY2FsLnNoCmV2YWxBZG1peCAtYmVhZ2xlIERhdGEvbmdzYWRtaXgvUEhfbWFmMDVfcHJ1bmVkX0JFQUdMRS5QTC5neiAtZm5hbWUgRGF0YS9uZ3NhZG1peC9QSF9wcnVuZWRfbWFmMDVfazIuZm9wdC5neiAtcW5hbWUgRGF0YS9uZ3NhZG1peC9QSF9wcnVuZWRfbWFmMDVfazIucW9wdCAtUCA4IC1vIG91dHB1dC5jb3JyZXMuazIudHh0CgpgYGAKCiMgUmVzdWx0cyBmcm9tIE5HU2FkbWl4CmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiNPdXRwdXQgZmlsZXMKcWZpbGVzPC1saXN0LmZpbGVzKCIuLi9EYXRhL25nc2FkbWl4LyIscGF0dGVybj0iLnFvcHQiKQoKb2ZpbGVzPC1saXN0LmZpbGVzKCIuLi9EYXRhL25nc2FkbWl4LyIscGF0dGVybj0ib3V0cHV0LmNvcnJlcyIpCgojcG9wdWxhdGlvbiBpbmZvCnBvcDwtcmVhZC5jc3YoIi4uL0RhdGEvU2FtcGxlX21ldGFkYXRhXzg5MnBvcHMuY3N2IikKCnBvcCRQb3B1bGF0aW9uLlllYXI8LWZhY3Rvcihwb3AkUG9wdWxhdGlvbi5ZZWFyLCBsZXZlbHM9YygiVEI5MSIsIlRCOTYiLCJUQjA2IiwiVEIxNyIsIlBXUzkxIiwiUFdTOTYiLCJQV1MwNyIsIlBXUzE3IiwiU1M5NiIsIlNTMDYiLCJTUzE3IiwiQkMxNyIsIldBMTciLCJDQTE3IikpCgpwb3BvcmRlcjwtcGFzdGUocG9wJFBvcHVsYXRpb24uWWVhcltvcmRlcihwb3AkUG9wdWxhdGlvbi5ZZWFyKV0pCnBvcF9vcmRlcjwtYygiVEI5MSIsIlRCOTYiLCJUQjA2IiwiVEIxNyIsIlBXUzkxIiwiUFdTOTYiLCJQV1MwNyIsIlBXUzE3IiwiU1M5NiIsIlNTMDYiLCJTUzE3IiwiQkMxNyIsIldBMTciLCJDQTE3IikKCiNjb2xvciBmb3IgcG9wdWxhdGlvbnMKI2xldmVscz1jKCJUQiIsIlBXUyIsIlNTIiwgIkJDIiwiV0EiLCJDQSIpKQojY29sb3JzPSBjb2xzICgiIzU2YjRlOSIgIiNjYzc5YTciICIjMDA5ZTczIiAiIzAwNzJiMiIgIiNkNTVlMDAiICIjZTY5ZjAwIiAiI2YwZTQ0MiIpCgpmb3IgKGkgaW4gMTpsZW5ndGgocWZpbGVzKSl7CiAgICAjIGV4dHJhY3QgSyBmcm9tIHRoZSBmaWxlIG5hbWUKICAgIG9uYW1lPC1vZmlsZXNbaV0KICAgIGs8LWFzLmludGVnZXIoc3Vic3RyKG9uYW1lLCAxNiwxNykpCiAgICAKICAgICNyZWFkIHRoZSBxb3B0IGZpbGUgZm9yIGs9awogICAgcTwtcmVhZC50YWJsZShwYXN0ZTAoIi4uL0RhdGEvbmdzYWRtaXgvIiwgcWZpbGVzW2ldKSkKICAgIAogICAgI29yZGVyIGFjY29yZGluZyB0byBwb3B1bGF0aW9uIGFuZCBwbG90IHRoZSBOR1NhZG1peCByZXN1bHRzCiAgICBxJGlkPC1wb3AkUG9wdWxhdGlvbi5ZZWFyCiAgICBxPC1xW29yZGVyKHEkaWQpLF0KICAgIAogICAgb3JkPC1vcmRlckluZHMocG9wID0gYXMudmVjdG9yKHBvcG9yZGVyKSwgcSA9IHFbLDE6KGkrMSldKQogICAgCiAgICB4bGFiZWxzPC1kYXRhLmZyYW1lKHg9dGFwcGx5KDE6bGVuZ3RoKHBvcG9yZGVyKSxsaXN0KHBvcG9yZGVyKSwgbWVhbikpCiAgICB4bGFiZWxzJHBvcDwtZmFjdG9yKHJvd25hbWVzKHhsYWJlbHMpLCBsZXZlbHM9cG9wX29yZGVyKQogICAgeGxhYmVsczwteGxhYmVsc1tvcmRlcih4bGFiZWxzJHBvcCksXQogICAgCiAgICAjIGMoJ1BXUyBjb2xvcicsICdUQiBjb2xvcicsICdDQSBjb2xvciIgKQogICAgI2lmIChpPT0xfGk9PTIpIGNvbG9ycz1jKDQsMiw3KQogICAgaWYgKGk9PTF8aT09MikgY29sb3JzPWMoMiw0LDcpCiAgICAjY29sb3JzPC1jKCIjY2M3OWE3IiwiIzU2YjRlOSIsICIjZTY5ZjAwIikKICAgICNpZiAoaT09MykgY29sb3JzPWMoNSw0LDcsMiwzKSAKICAgIGlmIChpPT0zKSBjb2xvcnM9Yyg1LDIsNyw0LDMpIAogICAgaWYgKGk9PTQpIGNvbG9ycz1jKDQsMiw1LDcsMykKCiAgICB7cG5nKHBhc3RlMCgiLi4vT3V0cHV0L25nc2FkbWl4L0FkbWl4X3Bsb3RfayIsaywiLnBuZyIpLCBoZWlnaHQgPSAzLjUsIHdpZHRoPTgsIHVuaXQ9ImluIiwgcmVzPTMwMCkKICAgIGJhcnBsb3QodChxWywxOihpKzIpXSlbLG9yZF0sY29sPWNvbG9ycyxzcGFjZT0wLGJvcmRlcj1OQSx4YXh0PSJuIix4bGFiPSJQb3B1bGF0aW9uIix5bGFiPXBhc3RlMCgiQWRtaXh0dXJlIHByb3BvcnRpb25zIGZvciBLPSIsaykpCiAgICB0ZXh0KHhsYWJlbHMkeCwtMC4wNSx4bGFiZWxzJHBvcCx4cGQ9VCwgc3J0PTkwLCBhZGo9MSxjZXg9MC44KQogICAgYWJsaW5lKHY9Y3Vtc3VtKHNhcHBseSh1bmlxdWUocG9wb3JkZXJbb3JkXSksZnVuY3Rpb24oeCl7c3VtKHBvcFtvcmQsIlBvcHVsYXRpb24uWWVhciJdPT14KX0pKSxjb2w9MSxsd2Q9MS4yKQogICAgZGV2Lm9mZigpfQogICAgCiAgICAjUGxvdCB0aGUgY29ycmVsYXRpb24gbWF0cml4IGZyb20gZXZhbEFkbWl4CiAgICByPC1yZWFkLnRhYmxlKHBhc3RlMCgiLi4vRGF0YS9uZ3NhZG1peC8iLG9maWxlc1tpXSkpCiAgICAKICAgICMgUGxvdCBjb3JyZWxhdGlvbiBvZiByZXNpZHVhbHMKICAgIHtwZGYocGFzdGUwKCIuLi9PdXRwdXQvbmdzYWRtaXgvZXZhbEFkbWl4X2NvcnBsb3RfayIsaywiLnBkZiIpLCBoZWlnaHQgPSA4LCB3aWR0aD0xMCkKICAgIHBsb3RDb3JSZXMoY29yX21hdCA9IHIsIHBvcCA9IGFzLnZlY3Rvcihwb3BbLCJQb3B1bGF0aW9uLlllYXIiXSksIG9yZCA9IG9yZCwgdGl0bGU9cGFzdGUwKCJFdmFsdWF0aW9uIG9mIGFkbWl4dHVyZSBwcm9wb3J0aW9ucyB3aXRoIEs9IixrKSwgbWF4X3o9MC4xLCBtaW5fej0tMC4xKQogICAgZGV2Lm9mZigpfQp9CmBgYAoKIVtdKC4uL091dHB1dC9uZ3NhZG1peC9BZG1peF9wbG90X2syX3NtYWxsLnBuZykKCiogQ29ycmVsYXRpb24gb2YgcmVzaWR1YWxzCgohW10oLi4vT3V0cHV0L25nc2FkbWl4L2V2YWxBZG1peF9jb3JwbG90X2syLnBuZykKCgoKIVtdKC4uL091dHB1dC9uZ3NhZG1peC9BZG1peF9wbG90X2szX3NtYWxsLnBuZykKCiFbXSguLi9PdXRwdXQvbmdzYWRtaXgvZXZhbEFkbWl4X2NvcnBsb3RfazMucG5nKQoKCiFbXSguLi9PdXRwdXQvbmdzYWRtaXgvQWRtaXhfcGxvdF9rNF9zbWFsbC5wbmcpCgohW10oLi4vT3V0cHV0L25nc2FkbWl4L2V2YWxBZG1peF9jb3JwbG90X2s0LnBuZykKCjxicj4KCiMgVXNlIENsdW1wYWsgdG8gY2hvb3NlIHRoZSBiZXN0IEsKKiBzZWUgaHR0cHM6Ly9naXRodWIuY29tL2FsZXhrcm9obi9BbWFyZ29zYVZvbGVUdXRvcmlhbHMvYmxvYi9tYXN0ZXIvbmdzQWRtaXhfdHV0b3JpYWwubWQKCiMjIFJ1biBOR1NhZG1peCAxMCB0aW1lcyBmb3IgZWFjaCBLIChLPSAzICYgNCkKKiBzZWUgUnVuTkdTYWRtaXguc2gKCiMjIENvbXBpbGUgYWxsIGxpa2VsaWhvb2QgbnVtYmVycyBmcm9tIGxvZyBmaWxlcyBpbnRvIDEgKGxvZ2ZpbGUpCgpgYGB7YmFzaCBldmFsPUZBTFNFfQojbGludXggY29kZSAod29uJ3Qgd29yayBmb3IgdW5peCkKKGZvciBsb2cgaW4gYGxzICoubG9nYDsgZG8gZ3JlcCAtb1AgJ1BoX3BydW5lZF9tYWYwNV9cS1teIF0rfGxpa2U9XEtbXiBdKycgJGxvZzsgZG9uZSkgPiBsb2dmaWxlX2szCihmb3IgbG9nIGluIGBscyAqLmxvZ2A7IGRvIGdyZXAgLW9QICdQaF9wcnVuZWRfbWFmMDVfXEtbXiBdK3xsaWtlPVxLW14gXSsnICRsb2c7IGRvbmUpID4gbG9nZmlsZV9rNApgYGAKCgojIyBSZWFkICdsb2dmaWxlJyAmIGNyZWF0ZSBhbiBpbnB1dCBmaWxlIGZvciBDbHVtcGFrCiogaHR0cDovL2NsdW1wYWsudGF1LmFjLmlsL2Jlc3RLLmh0bWwgIAoqIFVwbG9hZCB0aGUgbG9nIHByb2JhYmlsaXR5IHRhYmxlIGZpbGUgdG8gdGhlIHdlYnNpdGUgYW5kIHN1Ym1pdCB0aGUgZm9ybQoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbG9nMjwtcmVhZC50YWJsZSgiLi4vRGF0YS9uZ3NhZG1peC9sb2dmaWxlX2syIiwgc2VwPSJcdCIsIGhlYWRlciA9RkFMU0UpCmxvZzM8LXJlYWQudGFibGUoIi4uL0RhdGEvbmdzYWRtaXgvbG9nZmlsZV9rMyIsIHNlcD0iXHQiLCBoZWFkZXIgPUZBTFNFKQpsb2c0PC1yZWFkLnRhYmxlKCIuLi9EYXRhL25nc2FkbWl4L2xvZ2ZpbGVfazQiLCBzZXA9Ilx0IiwgaGVhZGVyID1GQUxTRSkKbG9nazI8LWxvZzJbYyhGQUxTRSxUUlVFKSxdCmxvZ2szPC1sb2czW2MoRkFMU0UsVFJVRSksXQpsb2drNDwtbG9nNFtjKEZBTFNFLFRSVUUpLF0KCmxvZ3M8LWRhdGEuZnJhbWUoSz1jKHJlcCgyLCB0aW1lcz0xMCkscmVwKDMsIHRpbWVzPTEwKSwgcmVwKDQsIHRpbWVzPTEwKSksIExpa2xpaG9vZD1jKGxvZ2syLGxvZ2szLCBsb2drNCkpCndyaXRlLnRhYmxlKGxvZ3MsICIuLi9PdXRwdXQvbmdzYWRtaXgvbG9ncy50eHQiLCBzZXA9Ilx0Iiwgcm93Lm5hbWVzID0gRiwgY29sLm5hbWVzID0gRiwgcXVvdGU9RikKIyBETyBOT1QgdXNlIHNwZWNpYWwgY2hhcmFjdGVyIGluIHRoZSBmaWxlIG5hbWUKI011c3QgaGF2ZSBhdCBsZWFzdCB0aHJlZSBLIHZhbHVlcwoKI3VwbG9hZCB0aGUgbG9ncy50eHQgdG8gQ2x1bXBhayB3ZWJzaXRlCiMgaHR0cDovL2NsdW1wYWsudGF1LmFjLmlsCgojJ0VzdGltYXRpbmcgdGhlIEJlc3QgSyAoZnJvbSBDbHVtcGFrKScKCiMgVGhlIG1ldGhvZCBvZiBFdmFubm8gZW5hYmxlcyB0aGUgdXNlciB0byBpZGVudGlmeSBhIHNpbmdsZSBrIHZhbHVlLCBvdXQgb2YgYSByYW5nZSBvZiBLIHZhbHVlcywgd2hpY2ggY2FwdHVyZXMgdGhlIHVwcGVybW9zdCAKIyBsZXZlbCBvZiBzdHJ1Y3R1cmUuIFRoaXMgbWV0aG9kIHdhcyBwdXJwb3NlZCBieSBFdm9ubm8gZXQgYWwuIGluIDIwMDUgKE1vbGVjdWxhciBFY29sb2d5IDE0LCAyMDA1KS4gSW4gYWRkaXRpb24sIHdlIGFsc28gdXNlCiMgbG4oUHIoWHxLKSAjdmFsdWVzIGluIG9yZGVyIHRvIGlkZW50aWZ5IHRoZSBrIGZvciB3aGljaCBQcihLPWspIGlzIGhpZ2hlc3QgKGFzIGRlc2NyaWJlZCBpbiBTVFJVQ1RVUkUncyBtYW51YWwsIHNlY3Rpb24gNS4xKS4KCiNTVFJVQ1RVUkUgbWFudWFsCiMnIGl0IGlzIG5vdCBpbmZyZXF1ZW50IHRoYXQgaW4gcmVhbCBkYXRhIHRoZSB2YWx1ZSBvZiBvdXIgbW9kZWwgY2hvaWNlIGNyaXRlcmlvbiBjb250aW51ZXMgdG8gaW5jcmVhc2Ugd2l0aCBpbmNyZWFzaW5nIEsuIAojIFRoZW4gaXQgdXN1YWxseSBtYWtlcyBzZW5zZSB0byBmb2N1cyBvbiB2YWx1ZXMgb2YgSyB0aGF0IGNhcHR1cmUgbW9zdCBvZiB0aGUgc3RydWN0dXJlIGluIHRoZSBkYXRhIGFuZCB0aGF0IHNlZW0gCiMgYmlvbG9naWNhbGx5IHNlbnNpYmxlLicKCiMgcGxvdCBhZG1peCB2YWx1ZXMKYGBgCgoqIFJlc3VscyBmcm9tIENMVU1QQUsgICAKKioiT3B0aW1hbCBLIGJ5IEV2YW5ubyBpczogMyAiKioKPGJyPgo8YnI+CgojIFJ1biBQb3B1bGF0aW9uIHNwZWNpZmljIE5HU2FkbWl4ICYgRlNUcnVjdAojIyBQV1MKLSBDcmVhdGUgYmFzaCBzY3JpdHB0cyB0byB0byBwcmVwIHRoZSBmaWxlcyAgCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgojQ3JlYXRlIGJlYWdsZSBmaWxlcyAoY3JlYXRlX2JlYWdsZS5zaCkKI3BvcHM8LWMoIlBXUzkxIiwiUFdTOTYiLCJQV1MwNyIsIlBXUzE3IikKc2luayhwYXN0ZTAoIi4uL0RhdGEvU2x1cm1zY3JpcHRzL2JlYWdsZV9wd3Muc2giKSkKY2F0KCIjIS9iaW4vYmFzaCAtbFxuXG4iKQpjYXQocGFzdGUwKCIjU0JBVENIIC0tam9iLW5hbWU9YmVhZ2xlIFxuIikpCmNhdChwYXN0ZTAoIiNTQkFUQ0ggLS1tZW09MTZHIFxuIikpIApjYXQocGFzdGUwKCIjU0JBVENIIC0tbnRhc2tzPTggXG4iKSkKY2F0KHBhc3RlMCgiI1NCQVRDSCAtZSBiZWFnbGUuZXJyICBcbiIpKQpjYXQocGFzdGUwKCIjU0JBVENIIC0tdGltZT03MjowMDowMCAgXG4iKSkKY2F0KHBhc3RlMCgiI1NCQVRDSCAtcCBoaWdoICBcbiIpKQpjYXQoIlxuIikKZm9yIChpIGluIDE6MjYpewogICBjYXQocGFzdGUwKCJ2Y2Z0b29scyAtLWd6dmNmIC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvcHJ1bmVkL3BydW5lZF9QV1Nvbmx5X21hZjA1XzUwLjUuNS52Y2YuZ3ogLS1jaHIgY2hyMSAtLW91dCAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL2JlYWdsZS9QV1Nvbmx5X3BydW5lZF9jIixpLCIgLS1CRUFHTEUtUEwgXG4iKSkKfQoKZm9yIChpIGluIDI6MjYpewogICAgY2F0KHBhc3RlMCgic2VkIC1lICcxLCAxZCcgPCAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL2JlYWdsZS9QV1Nvbmx5X3BydW5lZF9jIixpLCIuQkVBR0xFLlBMID4gL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9iZWFnbGUvUFdTb25seV9wcnVuZWRfYyIsaSwiLjIuQkVBR0xFLlBMIFxuIikpCn0KY2F0KCJcbiIpCgpjYXQoImNhdCAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL2JlYWdsZS9QV1Nvbmx5X3BydW5lZF9jMS5CRUFHTEUuUEwgIikgCmZvciAoaSBpbiAyOjI2KXsKICAgIGNhdChwYXN0ZTAoIi9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvYmVhZ2xlL1BXU29ubHlfcHJ1bmVkX2MiLGksIi4yLkJFQUdMRS5QTCAiKSkKfQpjYXQocGFzdGUwKCIgPiAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL2JlYWdsZS9QV1Nvbmx5X3BydW5lZF9CRUFHTEUuUEwgXG4iKSkKY2F0KCJnemlwIC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvYmVhZ2xlL1BXU29ubHlfcHJ1bmVkX0JFQUdMRS5QTCBcblxuIikKCnNpbmsoTlVMTCkKIApgYGAKCgojIyMgUnVuIE5HU2FkbWl4IGF0IEZhcm0gCmBgYHtyIGV2YWw9RkFMU0V9CiNjcmVhdGUgc2x1cm0gc2NyaXB0cyB0byBydW4gTkdTYWRtaXgKIyBydW4gaz0yLTUgKHJ1bl9OR1NhZG1peC5zaCkKI2ZpcnN0IHJ1biBvbmNlOgpmb3IgKGkgaW4gMjo2KSB7CiAgICBzaW5rKHBhc3RlMCgiLi4vRGF0YS9TbHVybXNjcmlwdHMvUnVuTkdTYWRtaXguIixpLCIuc2giKSkKICAgIGNhdCgiIyEvYmluL2Jhc2ggLWxcblxuIikKICAgIGNhdChwYXN0ZTAoIiNTQkFUQ0ggLS1qb2ItbmFtZT1hZG1peC4iLGksIlxuIikpCiAgICBjYXQoIiNTQkFUQ0ggLS1tZW09MTZHCiNTQkFUQ0ggLS1udGFza3M9OCBcbiIpCiAgICBjYXQocGFzdGUwKCIjU0JBVENIIC0tZXJyb3IgYWRtaXguIixpLCIuZXJyXG4iKSkKICAgIGNhdCgiI1NCQVRDSCAtLXRpbWU9NDg6MDA6MDAKI1NCQVRDSCAtLW1haWwtdXNlcj1rdGlzdEB1Y2RhdmlzLmVkdSAjI2VtYWlsIHlvdSB3aGVuIGpvYiBzdGFydHMsZW5kcyxldGMKI1NCQVRDSCAtLW1haWwtdHlwZT1BTEwKI1NCQVRDSCAtcCBoaWdoIFxuIikKICAgIGNhdCgiXG4iKQogICAgY2F0KCJtb2R1bGUgbG9hZCBhbmdzZFxuXG4iKQogICAgCiAgICBjYXQocGFzdGUwKCJOR1NhZG1peCAtbGlrZXMgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9iZWFnbGUvUFdTb25seV9wcnVuZWRfQkVBR0xFLlBMLmd6IC1LICIsaSwiIC1vIC9ob21lL2t0aXN0L3BoL2RhdGEvTkdTYWRtaXgvUFdTb25seV9wcnVuZWRfbWFmMDVfayIsaSwiIFxuIikpCiAgICBzaW5rKE5VTEwpCn0KCiMgUnVuIDEwIHRpbWVzIGZvciBlYWNoIEsgdG8gZmVlZCBpbnRvIENsdW1wYWsKCmBgYAoKCiMjIyBSdW4gZXZhbEFkbWl4IChsb2NhbGx5KQpgYGB7ciBldmFsPUZBTFNFfQpzaW5rKHBhc3RlMCgiLi4vRGF0YS9TbHVybXNjcmlwdHMvZXZhbEFkbWl4X3J1bmxvY2FsX3B3cy5zaCIpKQpjYXQoIiMhL2Jpbi9iYXNoIFxuXG4iKQoKI2V2YWxBZG1peF9ydW5sb2NhbF9wd3Muc2gKZm9yIChpIGluIDI6Nil7CiAgICBjYXQocGFzdGUwKCJldmFsQWRtaXggLWJlYWdsZSBEYXRhL25nc2FkbWl4L1BXU29ubHlfcHJ1bmVkX21hZjA1X0JFQUdMRS5QTC5neiAtZm5hbWUgRGF0YS9uZ3NhZG1peC9QV1Nvbmx5X3BydW5lZF9tYWYwNV9rIixpLCIuZm9wdC5neiAtcW5hbWUgRGF0YS9uZ3NhZG1peC9QV1Nvbmx5X3BydW5lZF9tYWYwNV9rIixpLCIucW9wdCAtUCA4IC1vIG91dHB1dC5jb3JyZXMuayIsaSwiLnR4dCBcbiIpKQp9CnNpbmsoTlVMTCkKYGBgCgojIyMgTkdTYWRtaXggYW5kIEV2YWxBZG1peCBvdXRwdXRzIGZvciBQV1MgIApgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojT3V0cHV0IGZpbGVzCnFmaWxlczwtbGlzdC5maWxlcygiLi4vRGF0YS9uZ3NhZG1peC8iLHBhdHRlcm49Il5QV1Nvbmx5LisucW9wdCIpCm9maWxlczwtbGlzdC5maWxlcygiLi4vRGF0YS9uZ3NhZG1peC8iLHBhdHRlcm49Il5QV1Nvbmx5LitvdXRwdXQuY29ycmVzIikKCiNwb3B1bGF0aW9uIGluZm8KcG9wPC1yZWFkLmNzdigiLi4vRGF0YS9TYW1wbGVfbWV0YWRhdGFfODkycG9wcy5jc3YiKQpwcG9wPC1wb3BbZ3JlcGwoIlBXUyIscG9wJFNhbXBsZSksXQpwcG9wJFBvcHVsYXRpb24uWWVhcjwtZmFjdG9yKHBwb3AkUG9wdWxhdGlvbi5ZZWFyLCBsZXZlbHM9YygiUFdTOTEiLCJQV1M5NiIsIlBXUzA3IiwiUFdTMTciKSkKcG9wb3JkZXI8LXBhc3RlKHBwb3AkUG9wdWxhdGlvbi5ZZWFyW29yZGVyKHBwb3AkUG9wdWxhdGlvbi5ZZWFyKV0pCnBvcF9vcmRlcjwtYygiUFdTOTEiLCJQV1M5NiIsIlBXUzA3IiwiUFdTMTciKQoKZm9yIChpIGluIDE6bGVuZ3RoKHFmaWxlcykpewogICAgIyBleHRyYWN0IEsgZnJvbSB0aGUgZmlsZSBuYW1lCiAgICBvbmFtZTwtb2ZpbGVzW2ldCiAgICBrPC1hcy5pbnRlZ2VyKHN0cl9leHRyYWN0KG9uYW1lLCAiW1s6ZGlnaXQ6XV0rIikpCiAgICAKICAgICNyZWFkIHRoZSBxb3B0IGZpbGUgZm9yIGs9awogICAgcTwtcmVhZC50YWJsZShwYXN0ZTAoIi4uL0RhdGEvbmdzYWRtaXgvIiwgcWZpbGVzW2ldKSkKICAgIAogICAgI29yZGVyIGFjY29yZGluZyB0byBwb3B1bGF0aW9uIGFuZCBwbG90IHRoZSBOR1NhZG1peCByZXN1bHRzCiAgICBxJGlkPC1wcG9wJFBvcHVsYXRpb24uWWVhcgogICAgcTwtcVtvcmRlcihxJGlkKSxdCiAgICAKICAgIG9yZDwtb3JkZXJJbmRzKHBvcCA9IGFzLnZlY3Rvcihwb3BvcmRlciksIHEgPSBxWywxOihpKzEpXSkKICAgIAogICAgeGxhYmVsczwtZGF0YS5mcmFtZSh4PXRhcHBseSgxOmxlbmd0aChwb3BvcmRlciksbGlzdChwb3BvcmRlciksIG1lYW4pKQogICAgeGxhYmVscyRwb3A8LWZhY3Rvcihyb3duYW1lcyh4bGFiZWxzKSwgbGV2ZWxzPXBvcF9vcmRlcikKICAgIHhsYWJlbHM8LXhsYWJlbHNbb3JkZXIoeGxhYmVscyRwb3ApLF0KICAgIAogICAgIyBjKCdQV1MgY29sb3InLCAnVEIgY29sb3InLCAnQ0EgY29sb3IiICkKICAgICNpZiAoaT09MXxpPT0yKSBjb2xvcnM9Yyg0LDIsNykKICAgIGlmIChpPT0xfGk9PTIpIGNvbG9ycz1jKDIsNCw3KQogICAgI2NvbG9yczwtYygiI2NjNzlhNyIsIiM1NmI0ZTkiLCAiI2U2OWYwMCIpCiAgICAjaWYgKGk9PTMpIGNvbG9ycz1jKDUsNCw3LDIsMykgCiAgICBpZiAoaT09MykgY29sb3JzPWMoNSwyLDcsNCwzKSAKICAgIGlmIChpPT00KSBjb2xvcnM9Yyg0LDIsNSw3LDMpCgogICAge3BuZyhwYXN0ZTAoIi4uL091dHB1dC9uZ3NhZG1peC9QV1Nvbmx5X0FkbWl4X3Bsb3RfayIsaywiLnBuZyIpLCBoZWlnaHQgPSAzLjUsIHdpZHRoPTgsIHVuaXQ9ImluIiwgcmVzPTMwMCkKICAgIGJhcnBsb3QodChxWywxOihpKzIpXSlbLG9yZF0sY29sPWNvbG9ycyxzcGFjZT0wLGJvcmRlcj1OQSx4YXh0PSJuIix4bGFiPSJQb3B1bGF0aW9uIix5bGFiPXBhc3RlMCgiQWRtaXh0dXJlIHByb3BvcnRpb25zIGZvciBLPSIsaykpCiAgICB0ZXh0KHhsYWJlbHMkeCwtMC4wNSx4bGFiZWxzJHBvcCx4cGQ9VCwgc3J0PTkwLCBhZGo9MSxjZXg9MC44KQogICAgYWJsaW5lKHY9Y3Vtc3VtKHNhcHBseSh1bmlxdWUocG9wb3JkZXJbb3JkXSksZnVuY3Rpb24oeCl7c3VtKHBwb3Bbb3JkLCJQb3B1bGF0aW9uLlllYXIiXT09eCl9KSksY29sPTEsbHdkPTEuMikKICAgIGRldi5vZmYoKX0KICAgIAogICAgI1Bsb3QgdGhlIGNvcnJlbGF0aW9uIG1hdHJpeCBmcm9tIGV2YWxBZG1peAogICAgcjwtcmVhZC50YWJsZShwYXN0ZTAoIi4uL0RhdGEvbmdzYWRtaXgvIixvZmlsZXNbaV0pKQogICAgCiAgICAjIFBsb3QgY29ycmVsYXRpb24gb2YgcmVzaWR1YWxzCiAgICB7cGRmKHBhc3RlMCgiLi4vT3V0cHV0L25nc2FkbWl4L1BXU29ubHlfZXZhbEFkbWl4X2NvcnBsb3RfayIsaywiLnBkZiIpLCBoZWlnaHQgPSA4LCB3aWR0aD0xMCkKICAgIHBsb3RDb3JSZXMoY29yX21hdCA9IHIsIHBvcCA9IGFzLnZlY3RvcihwcG9wWywiUG9wdWxhdGlvbi5ZZWFyIl0pLCBvcmQgPSBvcmQsIHRpdGxlPXBhc3RlMCgiRXZhbHVhdGlvbiBvZiBhZG1peHR1cmUgcHJvcG9ydGlvbnMgd2l0aCBLPSIsayksIG1heF96PTAuMSwgbWluX3o9LTAuMSkKICAgIGRldi5vZmYoKX0KfQoKYGBgCiFbXSguLi9PdXRwdXQvbmdzYWRtaXgvUFdTb25seV9BZG1peF9wbG90X2syLnBuZykKIVtdKC4uL091dHB1dC9uZ3NhZG1peC9QV1Nvbmx5X0FkbWl4X3Bsb3RfazMucG5nKQohW10oLi4vT3V0cHV0L25nc2FkbWl4L1BXU29ubHlfQWRtaXhfcGxvdF9rNC5wbmcpICAKCiFbXSguLi9PdXRwdXQvbmdzYWRtaXgvUFdTb25seV9BZG1peF9wbG90X2s1LnBuZykgIAoKCiMjIyBCZXN0IEsgZXN0aW1hdGUKKiBSdW4gZWFjaCBrIGZvciAxMCB0aW1lcyB0byBhc3Nlc3MgdGhlIGJlc3QgayAgCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiNjcmVhdGUgc2x1cm0gc2NyaXB0cyB0byBydW4gTkdTYWRtaXggeCAxMApmb3IgKGkgaW4gMjo2KSB7CiAgICBzaW5rKHBhc3RlMCgiLi4vRGF0YS9TbHVybXNjcmlwdHMvTkdTYWRtaXhQLiIsaSwiLnNoIikpCiAgICBjYXQoIiMhL2Jpbi9iYXNoIC1sXG5cbiIpCiAgICBjYXQocGFzdGUwKCIjU0JBVENIIC0tam9iLW5hbWU9YWRtaXguIixpLCJcbiIpKQogICAgY2F0KCIjU0JBVENIIC0tbWVtPTE2RwojU0JBVENIIC0tbnRhc2tzPTggXG4iKQogICAgY2F0KHBhc3RlMCgiI1NCQVRDSCAtLWVycm9yIGFkbWl4LiIsaSwiLmVyclxuIikpCiAgICBjYXQoIiNTQkFUQ0ggLS10aW1lPTMwMDowMDowMAojU0JBVENIIC0tbWFpbC11c2VyPWt0aXN0QHVjZGF2aXMuZWR1ICMjZW1haWwgeW91IHdoZW4gam9iIHN0YXJ0cyxlbmRzLGV0YwojU0JBVENIIC0tbWFpbC10eXBlPUFMTAojU0JBVENIIC1wIGhpZ2ggXG4iKQogICAgY2F0KCJcbiIpCiAgICBjYXQoIm1vZHVsZSBsb2FkIGFuZ3NkXG5cbiIpCiAgICAKICAgIGZvciAoaiBpbiAxOjEwKXsKICAgICAgICBjYXQocGFzdGUwKCJOR1NhZG1peCAtbGlrZXMgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9iZWFnbGUvUFdTb25seV9wcnVuZWRfbWFmMDVfQkVBR0xFLlBMLmd6IC1LICIsaSwiIC1vIC9ob21lL2t0aXN0L3BoL2RhdGEvTkdTYWRtaXgvUFdTb25seV9wcnVuZWRfbWFmMDVfayIsaSwiX3J1biIsaiwiIFxuIikpCiAgICB9CiAgICBzaW5rKE5VTEwpCn0KYGBgCgoKKiBDb21waWxlIGFsbCBsaWtlbGlob29kIG51bWJlcnMgZnJvbSBsb2cgZmlsZXMgaW50byAxIChsb2dmaWxlKSAgCmBgYHtiYXNoIGV2YWw9RkFMU0V9CiNsaW51eCBjb2RlICh3b24ndCB3b3JrIGZvciB1bml4KQooZm9yIGxvZyBpbiBgbHMgKi5sb2dgOyBkbyBncmVwIC1vUCAnUFdTb25seV9wcnVuZWRfbWFmMDVfXEtbXiBdK3xsaWtlPVxLW14gXSsnICRsb2c7IGRvbmUpID4gbG9nZmlsZV9rMwpgYGAKCiogU2x1cm1zY3JpcHRzIHRvIGNyZWF0ZSBsb2cgZmlsZXMKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0Kc2luayhwYXN0ZTAoIi4uL0RhdGEvU2x1cm1zY3JpcHRzL2xvZ2ZpbGVzUC5zaCIpKQpjYXQoIiMhL2Jpbi9iYXNoIC1sXG5cbiIpCmNhdChwYXN0ZTAoIiNTQkFUQ0ggLS1qb2ItbmFtZT1sb2dQIFxuIikpCmNhdCgiI1NCQVRDSCAtLW1lbT0xNkcKI1NCQVRDSCAtLW50YXNrcz04IFxuIikKY2F0KHBhc3RlMCgiI1NCQVRDSCAtLWVycm9yIGxvZ1AuZXJyXG4iKSkKY2F0KCIjU0JBVENIIC0tdGltZT0yNDowMDowMAojU0JBVENIIC1wIGhpZ2ggXG4iKQpjYXQoIlxuIikKZm9yIChrIGluIDI6Nil7CiAgICBjYXQocGFzdGUwKCJjZCAvaG9tZS9rdGlzdC9waC9kYXRhL05HU2FkbWl4L1BXU19rIixrLCIvIFxuIikpCiAgICBjYXQoIihmb3IgbG9nIGluIGBscyAqLmxvZ2A7IGRvIGdyZXAgLW9QICdsaWtlPVxcS1teIF0rJyAkbG9nOyBkb25lKSA+IHB3c19sb2dmaWxlX2siKQogICAgY2F0KHBhc3RlMChrICwiIFxuIikpCn0Kc2luayhOVUxMKQpgYGAKCiogUmVhZCAnbG9nZmlsZScgJiBjcmVhdGUgYW4gaW5wdXQgZmlsZSBmb3IgQ2x1bXBhawogICAgKiBodHRwOi8vY2x1bXBhay50YXUuYWMuaWwvYmVzdEsuaHRtbCAgCiAgICAqIFVwbG9hZCB0aGUgbG9nIHByb2JhYmlsaXR5IHRhYmxlIGZpbGUgdG8gdGhlIHdlYnNpdGUgYW5kIHN1Ym1pdCB0aGUgZm9ybQoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KI2xvZzI8LXJlYWQudGFibGUoIi4uL0RhdGEvbmdzYWRtaXgvUFdTL3B3c19sb2dfazIiLCBzZXA9Ilx0IiwgaGVhZGVyID1GQUxTRSkKI2xvZzM8LXJlYWQudGFibGUoIi4uL0RhdGEvbmdzYWRtaXgvUFdTL3B3c19sb2dfazMiLCBzZXA9Ilx0IiwgaGVhZGVyID1GQUxTRSkKI2xvZzQ8LXJlYWQudGFibGUoIi4uL0RhdGEvbmdzYWRtaXgvUFdTL3B3c19sb2dfazQiLCBzZXA9Ilx0IiwgaGVhZGVyID1GQUxTRSkKI2xvZzU8LXJlYWQudGFibGUoIi4uL0RhdGEvbmdzYWRtaXgvUFdTL3B3c19sb2dfazUiLCBzZXA9Ilx0IiwgaGVhZGVyID1GQUxTRSkKIwojbG9nazI8LWxvZzJbYyhGQUxTRSxGQUxTRSxUUlVFKSxdCiNsb2drMzwtbG9nM1tjKEZBTFNFLEZBTFNFLFRSVUUpLF0KI2xvZ2s0PC1sb2c0W2MoRkFMU0UsRkFMU0UsVFJVRSksXQojbG9nazU8LWxvZzVbYyhGQUxTRSxGQUxTRSxUUlVFKSxdCmxvZzI8LXJlYWQudGFibGUoIi4uL0RhdGEvbmdzYWRtaXgvUFdTL3B3c19sb2dmaWxlX2syIiwgc2VwPSJcdCIsIGhlYWRlciA9RkFMU0UpCmxvZzM8LXJlYWQudGFibGUoIi4uL0RhdGEvbmdzYWRtaXgvUFdTL3B3c19sb2dmaWxlX2szIiwgc2VwPSJcdCIsIGhlYWRlciA9RkFMU0UpCmxvZzQ8LXJlYWQudGFibGUoIi4uL0RhdGEvbmdzYWRtaXgvUFdTL3B3c19sb2dmaWxlX2s0Iiwgc2VwPSJcdCIsIGhlYWRlciA9RkFMU0UpCmxvZzU8LXJlYWQudGFibGUoIi4uL0RhdGEvbmdzYWRtaXgvUFdTL3B3c19sb2dmaWxlX2s1Iiwgc2VwPSJcdCIsIGhlYWRlciA9RkFMU0UpCmxvZzY8LXJlYWQudGFibGUoIi4uL0RhdGEvbmdzYWRtaXgvUFdTL3B3c19sb2dmaWxlX2s2Iiwgc2VwPSJcdCIsIGhlYWRlciA9RkFMU0UpCgpsb2dzMTwtZGF0YS5mcmFtZShLPWMocmVwKDIsIHRpbWVzPTEwKSxyZXAoMywgdGltZXM9MTApLCByZXAoNCwgdGltZXM9MTApLHJlcCg1LCB0aW1lcz0xMCkpLCBMaWtsaWhvb2Q9Yyhsb2cyJFYxLGxvZzMkVjEsIGxvZzQkVjEsIGxvZzUkVjEpKQoKbG9nczI8LWRhdGEuZnJhbWUoSz1jKHJlcCgyLCB0aW1lcz00KSxyZXAoMywgdGltZXM9NCksIHJlcCg0LCB0aW1lcz00KSxyZXAoNSwgdGltZXM9NCkscmVwKDYsIHRpbWVzPTQpKSwgTGlrbGlob29kPWMobG9nMiRWMVsxOjRdLGxvZzMkVjFbMTo0XSwgbG9nNCRWMVsxOjRdLCBsb2c1JFYxWzE6NF0sbG9nNiRWMVsxOjRdKSkKCgojbG9nczwtZGF0YS5mcmFtZShLPWMocmVwKDIsIHRpbWVzPTEwKSxyZXAoMywgdGltZXM9OSkpLCBMaWtsaWhvb2Q9Yyhsb2drMixsb2drMykpCiNsb2dzPC1kYXRhLmZyYW1lKEs9YyhyZXAoMiwgdGltZXM9NSkscmVwKDMsIHRpbWVzPTUpLCByZXAoNCwgdGltZXM9NSkscmVwKDUsIHRpbWVzPTUpKSwgTGlrbGlob29kPWMobG9nazJbMTo1XSxsb2drM1sxOjVdLCBsb2drNCwgbG9nazUpKQp3cml0ZS50YWJsZShsb2dzLCAiLi4vT3V0cHV0L25nc2FkbWl4L1BXU29ubHlfbG9ncy50eHQiLCBzZXA9Ilx0Iiwgcm93Lm5hbWVzID0gRiwgY29sLm5hbWVzID0gRiwgcXVvdGU9RikKd3JpdGUudGFibGUobG9nczEsICIuLi9PdXRwdXQvbmdzYWRtaXgvUFdTb25seV9sb2dzMS50eHQiLCBzZXA9Ilx0Iiwgcm93Lm5hbWVzID0gRiwgY29sLm5hbWVzID0gRiwgcXVvdGU9RikKd3JpdGUudGFibGUobG9nczIsICIuLi9PdXRwdXQvbmdzYWRtaXgvUFdTb25seV9sb2dzMi50eHQiLCBzZXA9Ilx0Iiwgcm93Lm5hbWVzID0gRiwgY29sLm5hbWVzID0gRiwgcXVvdGU9RikKCiMgRE8gTk9UIHVzZSBzcGVjaWFsIGNoYXJhY3RlciBpbiB0aGUgZmlsZSBuYW1lCiNNdXN0IGhhdmUgYXQgbGVhc3QgdGhyZWUgSyB2YWx1ZXMKCmBgYAoKKiBDTFVNUEFLIHN1Z2dlc3RzIEs9MyBhcyBvcHRpbWFsIGJ5IEV2YW5ubyBNZXRob2QKKiBIb3dldmVyLCBrIHdpdGggdGhlIGhpZ2hlc3QgUHJvYihLPWspIGlzOiA2IChvciBtYXggaykgIC0tbm90IHN1cmUgaG93IHRvIGludGVycHJldCwgYnV0IHN0aWNrIHRvIEs9MwoKIyMjIEZTVHJ1Y3QgIAoqIFJ1biBmb3IgYWxsIHZhbHVlcyBmb3IgY29tcGFyaXNvbgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKI2FsbDwtYygiVEI5MSIsIlRCOTYiLCJUQjA2IiwiVEIxNyIsIlBXUzkxIiwiUFdTOTYiLCJQV1MwNyIsIlBXUzE3IiwiU1M5NiIsIlNTMDYiLCJTUzE3IiwiQkMxNyIsIldBMTciLCJDQTE3IikKcG9wX2luZm88LXJlYWQuY3N2KCIuLi9EYXRhL1NhbXBsZV9tZXRhZGF0YV84OTJwb3BzLmNzdiIpCnB3czwtYygiUFdTOTEiLCJQV1M5NiIsIlBXUzA3IiwiUFdTMTciKQpwb3BfaW5mb1A8LXBvcF9pbmZvW3BvcF9pbmZvJHBvcD09IlBXUyIsXQpjb2xzNjwtYygnI2ZiYjRhZScsJyNiM2NkZTMnLCcjY2NlYmM1JywnI2RlY2JlNCcsJyNmZWQ5YTYnLCcjZmZmZmNjJykKCndpbGNveDwtbGlzdCgpCmZvciAoayBpbiAyOjYpewogICAgcW1hdDwtcmVhZC50YWJsZShwYXN0ZTAoIi4uL0RhdGEvbmdzYWRtaXgvUFdTb25seV9wcnVuZWRfbWFmMDVfayIsaywiLnFvcHQiKSwgaGVhZGVyID0gRikKICAgIHFtYXQ8LWNiaW5kKHBvcF9pbmZvUFssYygiU2FtcGxlIiwiUG9wdWxhdGlvbi5ZZWFyIildLCBxbWF0KQogICAgY29sbmFtZXMocW1hdClbMToyXTwtYygiaW5kIiwicG9wIikKICAgIHFtYXQkcG9wPC1mYWN0b3IocW1hdCRwb3AsIGxldmVscz1wd3MpCiAgICBxbWF0PC1xbWF0W29yZGVyKHFtYXQkcG9wKSxdCiAgICAKICAgIGttZWFuczwtYXBwbHkoYXMubWF0cml4KHFtYXRbcW1hdCRwb3A9PXB3c1sxXSwzOihrKzIpXSksMixtZWFuKQogICAga19vcmRlcjwtbmFtZXMoa21lYW5zW29yZGVyKGttZWFucywgZGVjcmVhc2luZyA9IFQpXSkKICAgIHFtYXQ8LXFtYXRbLGMoImluZCIsInBvcCIsa19vcmRlcildCiAgICBxbWF0X3NvcnRlZDwtZGF0YS5mcmFtZSgpCiAgICBmb3IgKGkgaW4gMTpsZW5ndGgocHdzKSl7CiAgICAgICAgZGY8LXFtYXRbcW1hdCRwb3A9PXB3c1tpXSxdCiAgICAgICAgZGY8LWRmW29yZGVyKGRmWyxjb2xuYW1lcyhkZilbY29sbmFtZXMoZGYpPT1rX29yZGVyWzFdXV0sZGZbLGNvbG5hbWVzKGRmKVtjb2xuYW1lcyhkZik9PWtfb3JkZXJba11dXSxkZWNyZWFzaW5nID0gYyhUUlVFLEZBTFNFKSwgbWV0aG9kPSJyYWRpeCIpLF0KICAgICAgICBxbWF0X3NvcnRlZDwtcmJpbmQocW1hdF9zb3J0ZWQsIGRmKQogICAgfQogICAgCiAgICBuaW5kPC1kYXRhLmZyYW1lKHBvcD1wd3MpCiAgICBuaW5kJG5bMV08LW5yb3cocW1hdFtxbWF0JHBvcD09cHdzWzFdLF0pCiAgICBuaW5kJG1pZFsxXTwtbmluZCRuWzFdLzIKICAgIGZvcihpIGluIDI6bGVuZ3RoKHB3cykpewogICAgICAgIG5vPC1ucm93KHFtYXRbcW1hdCRwb3A9PXB3c1tpXSxdKQogICAgICAgIG5pbmQkbltpXTwtbmluZCRuW2ktMV0rbm8KICAgICAgICBuaW5kJG1pZFtpXTwtbmluZCRuW2ktMV0rbm8vMgogICAgfQoKICAgIHFtPC1xbWF0X3NvcnRlZFssMjooaysyKV0KICAgIFFfcGxvdChRID0gcW0sSz1rKSsKICAgICAgICAgICAgZ2dwbG90Mjo6c2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWNvbHM2KSsKICAgICAgICAgICAgZ2dwbG90Mjo6c2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jb2xzNikrCiAgICAgICAgICAgIGdncGxvdDI6OnNjYWxlX3hfY29udGludW91cyhsYWJlbHM9cHdzLCBicmVha3M9bmluZCRtaWQpKwogICAgICAgICAgICB0aGVtZV9taW5pbWFsKCkreGxhYignJykreWxhYignJykreWxpbSgwLDEpKwogICAgICAgICAgICB0aGVtZShwYW5lbC5ncmlkPWVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTgpKSsKICAgICAgICAgICAgZ2dwbG90Mjo6YW5ub3RhdGUoJ3NlZ21lbnQnLCB4PW5pbmQkblsxOjNdKzAuNSx5PXJlcCgwLCB0aW1lcz0zKSx5ZW5kPXJlcCgxLCB0aW1lcz0zKSwgeGVuZD1uaW5kJG5bMTozXSswLjUsICAgICBjb2xvcj0iZ3JheTMwIiwgc2l6ZT0wLjMpCiAgICBnZ3NhdmUocGFzdGUwKCcuLi9PdXRwdXQvbmdzYWRtaXgvUFdTb25seV9wbG90X2snLGssJy5wbmcnKSwgd2lkdGggPSA4LCBoZWlnaHQgPSAzLjUsIGRwaT0zMDApCiAgICAgICAgICAgCiAgICAjY2FsY3VsYXRlIHN0YXRzCiAgICBRczwtbGlzdCgpICNRbWF0cml4CiAgICBmb3IgKGkgaW4gMTogbGVuZ3RoKHB3cykpewogICAgICAgIGRmPC1xbWF0W3FtYXQkcG9wPT1wd3NbaV0sXQogICAgICAgIFFzW1tpXV08LWRmCiAgICAgICAgbmFtZXMoUXMpW2ldPC1wd3NbaV0KICAgIH0gICAgICAgIAoKICAgIGJvb3RzdHJhcCA8LSBRX2Jvb3RzdHJhcChtYXRyaWNlcyA9IFFzLG5fcmVwbGljYXRlcyA9IDEwMCxLID0gayxzZWVkID0gMSkKICAgICNUaGlzIGRvZXMgbm90IHNhdmUgdGhlIHBsb3RzLi4uCiAgICB7cG5nKHBhc3RlMCgiLi4vT3V0cHV0L25nc2FkbWl4L1BXU29ubHlfZnN0cnVjdF9zdGF0c19rIixrLCIucG5nIiksIHdpZHRoPTEwLCBoZWlnaHQ9NywgdW5pdD0naW4nLCByZXM9MzAwKQogICAgY293cGxvdDo6cGxvdF9ncmlkKGJvb3RzdHJhcCRwbG90X2JveHBsb3QgKyBnZ3Bsb3QyOjpnZ3RpdGxlKCJCb3ggUGxvdCIpK2dncGxvdDI6OnNjYWxlX3hfZGlzY3JldGUobGFiZWxzPXB3cyksIAogICAgICAgICAgICAgICAgICAgICAgICAgICBib290c3RyYXAkcGxvdF92aW9saW4gKyBnZ3Bsb3QyOjpnZ3RpdGxlKCJWaW9saW4gUGxvdCIpK2dncGxvdDI6OnNjYWxlX3hfZGlzY3JldGUobGFiZWxzPXB3cyksIAogICAgICAgICAgICAgICAgICAgICAgICAgICBib290c3RyYXAkcGxvdF9lY2RmICsgZ2dwbG90Mjo6Z2d0aXRsZSgiRUNERiBQbG90IikgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2dwbG90Mjo6c2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiRGFyazIiLCBsYWJlbHM9cHdzKSwgbnJvdz0yKQogICAgZGV2Lm9mZigpfQoKICAgIHdpbGNveFtba11dPC1ib290c3RyYXAkdGVzdF9wYWlyd2lzZV93aWxjb3gKfQoKYGBgCgojIyMgRlNUcnVjdCBydW4gZm9yIG9wdGltYWwgSyAoSz0zKSAgCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnBvcF9pbmZvPC1yZWFkLmNzdigiLi4vRGF0YS9TYW1wbGVfbWV0YWRhdGFfODkycG9wcy5jc3YiKQpwd3M8LWMoIlBXUzkxIiwiUFdTOTYiLCJQV1MwNyIsIlBXUzE3IikKcG9wX2luZm9QPC1wb3BfaW5mb1twb3BfaW5mbyRwb3A9PSJQV1MiLF0KY29sczY8LWMoJyNmYmI0YWUnLCcjYjNjZGUzJywnI2NjZWJjNScsJyNkZWNiZTQnLCcjZmVkOWE2JywnI2ZmZmZjYycpCmNvbHMzPC1jKCcjOGRkM2M3JywnI2ZmZmZiMycsJyNiZWJhZGEnKQoKCnFtYXQ8LXJlYWQudGFibGUocGFzdGUwKCIuLi9EYXRhL25nc2FkbWl4L1BXU29ubHlfcHJ1bmVkX21hZjA1X2szLnFvcHQiKSwgaGVhZGVyID0gRikKcW1hdDwtY2JpbmQocG9wX2luZm9QWyxjKCJTYW1wbGUiLCJQb3B1bGF0aW9uLlllYXIiKV0sIHFtYXQpCmNvbG5hbWVzKHFtYXQpWzE6Ml08LWMoImluZCIsInBvcCIpCnFtYXQkcG9wPC1mYWN0b3IocW1hdCRwb3AsIGxldmVscz1wd3MpCnFtYXQ8LXFtYXRbb3JkZXIocW1hdCRwb3ApLF0KCmttZWFuczwtYXBwbHkoYXMubWF0cml4KHFtYXRbcW1hdCRwb3A9PXB3c1sxXSwzOjVdKSwyLG1lYW4pCmtfb3JkZXI8LW5hbWVzKGttZWFuc1tvcmRlcihrbWVhbnMsIGRlY3JlYXNpbmcgPSBUKV0pCnFtYXQ8LXFtYXRbLGMoImluZCIsInBvcCIsa19vcmRlcildCnFtYXRfc29ydGVkPC1kYXRhLmZyYW1lKCkKZm9yIChpIGluIDE6bGVuZ3RoKHB3cykpewogICAgICAgIGRmPC1xbWF0W3FtYXQkcG9wPT1wd3NbaV0sXQogICAgICAgIGRmPC1kZltvcmRlcihkZlssY29sbmFtZXMoZGYpW2NvbG5hbWVzKGRmKT09a19vcmRlclsxXV1dLGRmWyxjb2xuYW1lcyhkZilbY29sbmFtZXMoZGYpPT1rX29yZGVyWzNdXV0sZGVjcmVhc2luZyA9IGMoVFJVRSxGQUxTRSksIG1ldGhvZD0icmFkaXgiKSxdCiAgICAgICAgcW1hdF9zb3J0ZWQ8LXJiaW5kKHFtYXRfc29ydGVkLCBkZikKfQogICAgCmZvciAoaSBpbiAxOmxlbmd0aChwd3MpKXsKICAgICAgICBkZjwtcW1hdFtxbWF0JHBvcD09cHdzW2ldLF0KICAgICAgICBkZjwtZGZbb3JkZXIoZGZbLGNvbG5hbWVzKGRmKVtjb2xuYW1lcyhkZik9PWtfb3JkZXJbMl1dXSxkZWNyZWFzaW5nID0gYyhUUlVFKSwgbWV0aG9kPSJyYWRpeCIpLF0KICAgICAgICBxbWF0X3NvcnRlZDwtcmJpbmQocW1hdF9zb3J0ZWQsIGRmKQp9Cm5pbmQ8LWRhdGEuZnJhbWUocG9wPXB3cykKbmluZCRuWzFdPC1ucm93KHFtYXRbcW1hdCRwb3A9PXB3c1sxXSxdKQpuaW5kJG1pZFsxXTwtbmluZCRuWzFdLzIKZm9yKGkgaW4gMjpsZW5ndGgocHdzKSl7CiAgICBubzwtbnJvdyhxbWF0W3FtYXQkcG9wPT1wd3NbaV0sXSkKICAgIG5pbmQkbltpXTwtbmluZCRuW2ktMV0rbm8KICAgIG5pbmQkbWlkW2ldPC1uaW5kJG5baS0xXStuby8yCn0KClFfcGxvdChRID0gcW1hdF9zb3J0ZWQsSz0zKSsKICAgICAgICBnZ3Bsb3QyOjpzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9Y29sczMpKwogICAgICAgIGdncGxvdDI6OnNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9Y29sczMpKwogICAgICAgIGdncGxvdDI6OnNjYWxlX3hfY29udGludW91cyhsYWJlbHM9cHdzLCBicmVha3M9bmluZCRtaWQpKwogICAgICAgIHRoZW1lX21pbmltYWwoKSt4bGFiKCcnKSt5bGFiKCcnKSsKICAgICAgICB0aGVtZShwYW5lbC5ncmlkPWVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTgpKSsKICAgICAgICBnZ3Bsb3QyOjphbm5vdGF0ZSgnc2VnbWVudCcsIHg9bmluZCRuWzE6M10rMC41LHk9cmVwKDAsIHRpbWVzPTMpLHllbmQ9cmVwKDEsIHRpbWVzPTMpLCB4ZW5kPW5pbmQkblsxOjNdKzAuNSwgICAgIGNvbG9yPSJncmF5MzAiLCBzaXplPTAuMykKZ2dzYXZlKHBhc3RlMCgnLi4vT3V0cHV0L25nc2FkbWl4L1BXU29ubHlfT3B0aW1hbEszLnBuZycpLCB3aWR0aCA9IDgsIGhlaWdodCA9IDMuNSwgZHBpPTMwMCkKICAgICAgICAgICAKI2NhbGN1bGF0ZSBzdGF0cwpRczwtbGlzdCgpICNRbWF0cml4CmZvciAoaSBpbiAxOiBsZW5ndGgocHdzKSl7CiAgICBkZjwtcW1hdFtxbWF0JHBvcD09cHdzW2ldLF0KICAgIFFzW1tpXV08LWRmCiAgICBuYW1lcyhRcylbaV08LXB3c1tpXQp9ICAgICAgICAKYm9vdHN0cmFwIDwtIFFfYm9vdHN0cmFwKG1hdHJpY2VzID0gUXMsbl9yZXBsaWNhdGVzID0gMTAwLEsgPSAzLHNlZWQgPSAxKQojVGhpcyBkb2VzIG5vdCBzYXZlIHRoZSBwbG90cy4uLgp7cG5nKHBhc3RlMCgiLi4vT3V0cHV0L25nc2FkbWl4L1BXU29ubHlfZnN0cnVjdF9zdGF0c19PcHRLMy5wbmciKSwgd2lkdGg9MTAsIGhlaWdodD03LCB1bml0PSdpbicsIHJlcz0zMDApCmNvd3Bsb3Q6OnBsb3RfZ3JpZChib290c3RyYXAkcGxvdF9ib3hwbG90ICsgZ2dwbG90Mjo6Z2d0aXRsZSgiQm94IFBsb3QiKStnZ3Bsb3QyOjpzY2FsZV94X2Rpc2NyZXRlKGxhYmVscz1wd3MpLCAKICAgICAgICAgICAgICAgICAgICAgICBib290c3RyYXAkcGxvdF92aW9saW4gKyBnZ3Bsb3QyOjpnZ3RpdGxlKCJWaW9saW4gUGxvdCIpK2dncGxvdDI6OnNjYWxlX3hfZGlzY3JldGUobGFiZWxzPXB3cyksIAogICAgICAgICAgICAgICAgICAgICAgIGJvb3RzdHJhcCRwbG90X2VjZGYgKyBnZ3Bsb3QyOjpnZ3RpdGxlKCJFQ0RGIFBsb3QiKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZ3Bsb3QyOjpzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIsIGxhYmVscz1wd3MpLCBucm93PTIpCmRldi5vZmYoKX0KCmJvb3RzdHJhcCR0ZXN0X3BhaXJ3aXNlX3dpbGNveAoKIyAgICAgIFBXUzkxICAgUFdTOTYgICBQV1MwNyAgCiNQV1M5NiA8IDJlLTE2IC0gICAgICAgLSAgICAgIAojUFdTMDcgPCAyZS0xNiAwLjEzICAgIC0gICAgICAKI1BXUzE3IDMuNmUtMDcgMS4wZS0xNCA8IDJlLTE2CiMKI1AgdmFsdWUgYWRqdXN0bWVudCBtZXRob2Q6IGhvbG0gCgpib290c3RyYXAkdGVzdF9rcnVza2FsX3dhbGxpcwojZGF0YTogIGFsbF9zdGF0cyRyYXRpbyBieSBhbGxfc3RhdHMkTWF0cml4CiNLcnVza2FsLVdhbGxpcyBjaGktc3F1YXJlZCA9IDIwOS4xOCwgZGYgPSAzLCBwLXZhbHVlIDwgMi4yZS0xNgoKClBXU19rM19zdGF0aXN0aWNzPC1ib290c3RyYXAkc3RhdGlzdGljcwpgYGAKCntwbmcocGFzdGUwKCJPdXRwdXQvbmdzYWRtaXgvUFdTb25seV9mc3RydWN0X3N0YXRzX09wdEszLnBuZyIpLCB3aWR0aD0xMCwgaGVpZ2h0PTcsIHVuaXQ9J2luJywgcmVzPTMwMCkKY293cGxvdDo6cGxvdF9ncmlkKGJvb3RzdHJhcCRwbG90X2JveHBsb3QgKyBnZ3Bsb3QyOjpnZ3RpdGxlKCJCb3ggUGxvdCIpK2dncGxvdDI6OnNjYWxlX3hfZGlzY3JldGUobGFiZWxzPXB3cyksIAogICAgICAgICAgICAgICAgICAgICAgIGJvb3RzdHJhcCRwbG90X3Zpb2xpbiArIGdncGxvdDI6OmdndGl0bGUoIlZpb2xpbiBQbG90IikrZ2dwbG90Mjo6c2NhbGVfeF9kaXNjcmV0ZShsYWJlbHM9cHdzKSwgCiAgICAgICAgICAgICAgICAgICAgICAgYm9vdHN0cmFwJHBsb3RfZWNkZiArIGdncGxvdDI6OmdndGl0bGUoIkVDREYgUGxvdCIpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdncGxvdDI6OnNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIiwgbGFiZWxzPXB3cyksIG5yb3c9MikKZGV2Lm9mZigpfQoKCiFbXSguLi9PdXRwdXQvbmdzYWRtaXgvUFdTb25seV9PcHRpbWFsSzMucG5nKQoKIVtdKC4uL091dHB1dC9uZ3NhZG1peC9QV1Nvbmx5X2ZzdHJ1Y3Rfc3RhdHNfT3B0SzMucG5nKQoKPGJyPgoKIyMgVEIKCmBgYHtiYXNoIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiNmaXJzdCBjcmVhdGUgcGVkL2JlZCBmaWxlcyB3aXRoIGFkZGluZyB2YXJpYW50IGlkCm1vZHVsZSBsb2FkIHBsaW5rCnBsaW5rIC0tdmNmIC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvVEJvbmx5X05TMC41X21hZjA1LnZjZi5neiAtLXNldC1taXNzaW5nLXZhci1pZHMgQDojW3BoXVxcJHIsXFwkYSAtLW1ha2UtYmVkIC0tb3V0IC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvcGxpbmtmaWxlcy9UQm9ubHlfTlMwLjVfbWFmMDUKCnBsaW5rIC0tYmZpbGUgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9wbGlua2ZpbGVzL1RCb25seV9OUzAuNV9tYWYwNSAtLXJlY29kZSAtLXRhYiAtLW91dCAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL3BsaW5rZmlsZXMvVEJvbmx5X05TMC41X21hZjA1CgojZmluZCBoaWdobHkgY29ycmVsYXRlZCBzaXRlcyBmb3IgcHJ1bmluZwpwbGluayAtLWZpbGUgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9wbGlua2ZpbGVzL1RCb25seV9OUzAuNV9tYWYwNSAtLWluZGVwLXBhaXJ3aXNlIDUwJ2tiJyA1IDAuNSAtLW91dCAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL3BsaW5rZmlsZXMvVEJvbmx5X05TMC41X21hZjA1XzUwXzVfMC41CgojUmVmb3JtYXQgcHJ1bi5pbiBmaWxlIHdpdGggcnVubmluZyB0aGUgcmVmb3JtYXRfcHJ1bmluLlIKUgpzb3VyY2UoInJlZm9ybWF0X3BydW5pbi5SIikKcmVmb3JtYXRfcHJ1bmluKCJwaC9kYXRhL25ld192Y2YvTUQ3MDAwL3BsaW5rZmlsZXMvVEJvbmx5X05TMC41X21hZjA1XzUwXzVfMC41LnBydW5lLmluIikKcXVpdCgpCgojIyBVc2UgYmNmdG9vbHMgdG8gc3Vic2V0IHRoZSBWQ0YgZmlsZSB3aXRoIC5wcnVuZS5pbi5zaXRlcy50eHQKYmNmdG9vbHMgaW5kZXggL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9UQm9ubHlfTlMwLjVfbWFmMDUudmNmLmd6IAoKYmNmdG9vbHMgdmlldyAtUiAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL3BsaW5rZmlsZXMvVEJvbmx5X05TMC41X21hZjA1XzUwXzVfMC41LnBydW5lLmluLnNpdGVzLnR4dCAgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9UQm9ubHlfTlMwLjVfbWFmMDUudmNmLmd6ID4gL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9wcnVuZWQvVEJvbmx5X05TMC41X21hZjA1X3BydW5lZC52Y2YKCmJnemlwIC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvcHJ1bmVkL1RCb25seV9OUzAuNV9tYWYwNV9wcnVuZWQudmNmCmBgYAoKYGBge3IgZXZhbD1GQUxTRX0KIyMgQ3JlYXRlIGJlYWdsZSBmaWxlcwpzaW5rKHBhc3RlMCgiLi4vRGF0YS9TbHVybXNjcmlwdHMvYmVhZ2xlX3RiLnNoIikpCmNhdCgiIyEvYmluL2Jhc2ggLWxcblxuIikKY2F0KHBhc3RlMCgiI1NCQVRDSCAtLWpvYi1uYW1lPWJlYWdsZSBcbiIpKQpjYXQocGFzdGUwKCIjU0JBVENIIC0tbWVtPTE2RyBcbiIpKSAKY2F0KHBhc3RlMCgiI1NCQVRDSCAtLW50YXNrcz04IFxuIikpCmNhdChwYXN0ZTAoIiNTQkFUQ0ggLWUgYmVhZ2xlLmVyciAgXG4iKSkKY2F0KHBhc3RlMCgiI1NCQVRDSCAtLXRpbWU9NzI6MDA6MDAgIFxuIikpCmNhdChwYXN0ZTAoIiNTQkFUQ0ggLXAgaGlnaCAgXG4iKSkKY2F0KCJcbiIpCmZvciAoaSBpbiAxOjI2KXsKICAgY2F0KHBhc3RlMCgidmNmdG9vbHMgLS1nenZjZiAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL3BydW5lZC9UQm9ubHlfTlMwLjVfbWFmMDVfcHJ1bmVkLnZjZi5neiAtLWNociBjaHIxIC0tb3V0IC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvYmVhZ2xlL1RCb25seV9wcnVuZWRfYyIsaSwiIC0tQkVBR0xFLVBMIFxuIikpCn0KY2F0KCJcbiIpCmZvciAoaSBpbiAyOjI2KXsKICAgIGNhdChwYXN0ZTAoInNlZCAtZSAnMSwgMWQnIDwgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9iZWFnbGUvVEJvbmx5X3BydW5lZF9jIixpLCIuQkVBR0xFLlBMID4gL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9iZWFnbGUvVEJvbmx5X3BydW5lZF9jIixpLCIuMi5CRUFHTEUuUEwgXG4iKSkKfQpjYXQoIlxuIikKCmNhdCgiY2F0IC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvYmVhZ2xlL1RCb25seV9wcnVuZWRfYzEuQkVBR0xFLlBMICIpIApmb3IgKGkgaW4gMjoyNil7CiAgICBjYXQocGFzdGUwKCIvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL2JlYWdsZS9UQm9ubHlfcHJ1bmVkX2MiLGksIi4yLkJFQUdMRS5QTCAiKSkKfQpjYXQocGFzdGUwKCIgPiAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL2JlYWdsZS9UQm9ubHlfcHJ1bmVkX0JFQUdMRS5QTCBcbiIpKQpjYXQoImd6aXAgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9iZWFnbGUvVEJvbmx5X3BydW5lZF9CRUFHTEUuUEwgXG5cbiIpCgpzaW5rKE5VTEwpCgojZmlyc3QgcnVuIG9uY2U6CmZvciAoaSBpbiAyOjYpIHsKICAgIHNpbmsocGFzdGUwKCIuLi9EYXRhL1NsdXJtc2NyaXB0cy9SdW5OR1NhZG1peCIsaSwiLnNoIikpCiAgICBjYXQoIiMhL2Jpbi9iYXNoIC1sXG5cbiIpCiAgICBjYXQocGFzdGUwKCIjU0JBVENIIC0tam9iLW5hbWU9YWRtaXgiLGksIlxuIikpCiAgICBjYXQoIiNTQkFUQ0ggLS1tZW09MTZHCiNTQkFUQ0ggLS1udGFza3M9OCBcbiIpCiAgICBjYXQocGFzdGUwKCIjU0JBVENIIC0tZXJyb3IgYWRtaXgiLGksIi5lcnJcbiIpKQogICAgY2F0KCIjU0JBVENIIC0tdGltZT00ODowMDowMAojU0JBVENIIC0tbWFpbC11c2VyPWt0aXN0QHVjZGF2aXMuZWR1ICMjZW1haWwgeW91IHdoZW4gam9iIHN0YXJ0cyxlbmRzLGV0YwojU0JBVENIIC0tbWFpbC10eXBlPUFMTAojU0JBVENIIC1wIGhpZ2ggXG4iKQogICAgY2F0KCJcbiIpCiAgICBjYXQoIm1vZHVsZSBsb2FkIGFuZ3NkXG5cbiIpCiAgICAKICAgIGNhdChwYXN0ZTAoIk5HU2FkbWl4IC1saWtlcyAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL2JlYWdsZS9UQm9ubHlfcHJ1bmVkX0JFQUdMRS5QTC5neiAtSyAiLGksIiAtbyAvaG9tZS9rdGlzdC9waC9kYXRhL05HU2FkbWl4L1BXU29ubHlfcHJ1bmVkX21hZjA1X2siLGksIiBcbiIpKQogICAgc2luayhOVUxMKQp9CgoKCmBgYAoKIyMjIFJ1biBldmFsQWRtaXggZm9yIFRCIChsb2NhbGx5KQpgYGB7ciBldmFsPUZBTFNFfQpzaW5rKHBhc3RlMCgiLi4vRGF0YS9TbHVybXNjcmlwdHMvZXZhbEFkbWl4X3J1bmxvY2FsX3RiLnNoIikpCmNhdCgiIyEvYmluL2Jhc2ggXG5cbiIpCmZvciAoaSBpbiAyOjYpewogICAgY2F0KHBhc3RlMCgiZXZhbEFkbWl4IC1iZWFnbGUgRGF0YS9uZ3NhZG1peC9UQi9UQm9ubHlfcHJ1bmVkX21hZjA1X0JFQUdMRS5QTC5neiAtZm5hbWUgRGF0YS9uZ3NhZG1peC9UQi9UQm9ubHlfcHJ1bmVkX21hZjA1X2siLGksIi5mb3B0Lmd6IC1xbmFtZSBEYXRhL25nc2FkbWl4L1RCL1RCb25seV9wcnVuZWRfbWFmMDVfayIsaSwiLnFvcHQgLVAgOCAtbyBUQm9ubHkub3V0cHV0LmNvcnJlcy5rIixpLCIudHh0IFxuIikpCn0Kc2luayhOVUxMKQpgYGAKCgojIyMgTkdTYWRtaXggYW5kIEV2YWxBZG1peCBvdXRwdXRzIGZvciBUQgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojT3V0cHV0IGZpbGVzCnFmaWxlczwtbGlzdC5maWxlcygiLi4vRGF0YS9uZ3NhZG1peC9UQi8iLHBhdHRlcm49Il5UQm9ubHkuKy5xb3B0IikKb2ZpbGVzPC1saXN0LmZpbGVzKCIuLi9EYXRhL25nc2FkbWl4L1RCLyIscGF0dGVybj0iXlRCb25seS4rb3V0cHV0LmNvcnJlcyIpCgojcG9wdWxhdGlvbiBpbmZvCnBvcDwtcmVhZC5jc3YoIi4uL0RhdGEvU2FtcGxlX21ldGFkYXRhXzg5MnBvcHMuY3N2IikKdHBvcDwtcG9wW2dyZXBsKCJUQiIscG9wJFNhbXBsZSksXQp0cG9wJFBvcHVsYXRpb24uWWVhcjwtZmFjdG9yKHRwb3AkUG9wdWxhdGlvbi5ZZWFyLCBsZXZlbHM9YygiVEI5MSIsIlRCOTYiLCJUQjA2IiwiVEIxNyIpKQp0cG9wb3JkZXI8LXBhc3RlKHRwb3AkUG9wdWxhdGlvbi5ZZWFyW29yZGVyKHRwb3AkUG9wdWxhdGlvbi5ZZWFyKV0pCnRwb3Bfb3JkZXI8LWMoIlRCOTEiLCJUQjk2IiwiVEIwNiIsIlRCMTciKQoKZm9yIChpIGluIDE6bGVuZ3RoKHFmaWxlcykpewogICAgIyBleHRyYWN0IEsgZnJvbSB0aGUgZmlsZSBuYW1lCiAgICBvbmFtZTwtb2ZpbGVzW2ldCiAgICBrPC1hcy5pbnRlZ2VyKHN0cl9leHRyYWN0KG9uYW1lLCAiW1s6ZGlnaXQ6XV0rIikpCiAgICAKICAgICNyZWFkIHRoZSBxb3B0IGZpbGUgZm9yIGs9awogICAgcTwtcmVhZC50YWJsZShwYXN0ZTAoIi4uL0RhdGEvbmdzYWRtaXgvVEIvIiwgcWZpbGVzW2ldKSkKICAgIAogICAgI29yZGVyIGFjY29yZGluZyB0byBwb3B1bGF0aW9uIGFuZCBwbG90IHRoZSBOR1NhZG1peCByZXN1bHRzCiAgICBxJGlkPC10cG9wJFBvcHVsYXRpb24uWWVhcgogICAgcTwtcVtvcmRlcihxJGlkKSxdCiAgICAKICAgIG9yZDwtb3JkZXJJbmRzKHBvcCA9IGFzLnZlY3Rvcih0cG9wb3JkZXIpLCBxID0gcVssMTooaSsxKV0pCiAgICAKICAgIHhsYWJlbHM8LWRhdGEuZnJhbWUoeD10YXBwbHkoMTpsZW5ndGgodHBvcG9yZGVyKSxsaXN0KHRwb3BvcmRlciksIG1lYW4pKQogICAgeGxhYmVscyRwb3A8LWZhY3Rvcihyb3duYW1lcyh4bGFiZWxzKSwgbGV2ZWxzPXRwb3Bfb3JkZXIpCiAgICB4bGFiZWxzPC14bGFiZWxzW29yZGVyKHhsYWJlbHMkcG9wKSxdCiAgICAKICAgICMgYygnUFdTIGNvbG9yJywgJ1RCIGNvbG9yJywgJ0NBIGNvbG9yIiApCiAgICAjaWYgKGk9PTF8aT09MikgY29sb3JzPWMoNCwyLDcpCiAgICBpZiAoaT09MXxpPT0yKSBjb2xvcnM9YygyLDQsNykKICAgICNjb2xvcnM8LWMoIiNjYzc5YTciLCIjNTZiNGU5IiwgIiNlNjlmMDAiKQogICAgI2lmIChpPT0zKSBjb2xvcnM9Yyg1LDQsNywyLDMpIAogICAgaWYgKGk9PTMpIGNvbG9ycz1jKDUsMiw3LDQsMykgCiAgICBpZiAoaT09NCkgY29sb3JzPWMoNCwyLDUsNywzKQoKICAgIHtwbmcocGFzdGUwKCIuLi9PdXRwdXQvbmdzYWRtaXgvVEJvbmx5X0FkbWl4X3Bsb3RfayIsaywiLnBuZyIpLCBoZWlnaHQgPSAzLjUsIHdpZHRoPTgsIHVuaXQ9ImluIiwgcmVzPTMwMCkKICAgIGJhcnBsb3QodChxWywxOihpKzIpXSlbLG9yZF0sY29sPWNvbG9ycyxzcGFjZT0wLGJvcmRlcj1OQSx4YXh0PSJuIix4bGFiPSJQb3B1bGF0aW9uIix5bGFiPXBhc3RlMCgiQWRtaXh0dXJlIHByb3BvcnRpb25zIGZvciBLPSIsaykpCiAgICB0ZXh0KHhsYWJlbHMkeCwtMC4wNSx4bGFiZWxzJHBvcCx4cGQ9VCwgc3J0PTkwLCBhZGo9MSxjZXg9MC44KQogICAgYWJsaW5lKHY9Y3Vtc3VtKHNhcHBseSh1bmlxdWUodHBvcG9yZGVyW29yZF0pLGZ1bmN0aW9uKHgpe3N1bSh0cG9wW29yZCwiUG9wdWxhdGlvbi5ZZWFyIl09PXgpfSkpLGNvbD0xLGx3ZD0xLjIpCiAgICBkZXYub2ZmKCl9CiAgICAKICAgICNQbG90IHRoZSBjb3JyZWxhdGlvbiBtYXRyaXggZnJvbSBldmFsQWRtaXgKICAgIHI8LXJlYWQudGFibGUocGFzdGUwKCIuLi9EYXRhL25nc2FkbWl4L1RCLyIsb2ZpbGVzW2ldKSkKICAgIAogICAgIyBQbG90IGNvcnJlbGF0aW9uIG9mIHJlc2lkdWFscwogICAge3BkZihwYXN0ZTAoIi4uL091dHB1dC9uZ3NhZG1peC9UQm9ubHlfZXZhbEFkbWl4X2NvcnBsb3RfayIsaywiLnBkZiIpLCBoZWlnaHQgPSA4LCB3aWR0aD0xMCkKICAgIHBsb3RDb3JSZXMoY29yX21hdCA9IHIsIHBvcCA9IGFzLnZlY3Rvcih0cG9wWywiUG9wdWxhdGlvbi5ZZWFyIl0pLCBvcmQgPSBvcmQsIHRpdGxlPXBhc3RlMCgiRXZhbHVhdGlvbiBvZiBhZG1peHR1cmUgcHJvcG9ydGlvbnMgd2l0aCBLPSIsayksIG1heF96PTAuMSwgbWluX3o9LTAuMSkKICAgIGRldi5vZmYoKX0KfQoKYGBgCiFbXSguLi9PdXRwdXQvbmdzYWRtaXgvVEJvbmx5X0FkbWl4X3Bsb3RfazIucG5nKQoKIVtdKC4uL091dHB1dC9uZ3NhZG1peC9UQm9ubHlfQWRtaXhfcGxvdF9rMy5wbmcpCgohW10oLi4vT3V0cHV0L25nc2FkbWl4L1RCb25seV9BZG1peF9wbG90X2s0LnBuZykKICAKIVtdKC4uL091dHB1dC9uZ3NhZG1peC9UQm9ubHlfQWRtaXhfcGxvdF9rNS5wbmcpICAKICAKIyMjIFJ1biBlYWNoIGsgZm9yIDUgdGltZXMgdG8gYXNzZXNzIHRoZSBiZXN0IGsgIChUQikKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KI2NyZWF0ZSBzbHVybSBzY3JpcHRzIHRvIHJ1biBOR1NhZG1peCB4IDEwCmZvciAoaSBpbiAyOjYpIHsKICAgIHNpbmsocGFzdGUwKCIuLi9EYXRhL1NsdXJtc2NyaXB0cy9OR1NhZG1peFQuIixpLCIuc2giKSkKICAgIGNhdCgiIyEvYmluL2Jhc2ggLWxcblxuIikKICAgIGNhdChwYXN0ZTAoIiNTQkFUQ0ggLS1qb2ItbmFtZT1hZG1peFQuIixpLCJcbiIpKQogICAgY2F0KCIjU0JBVENIIC0tbWVtPTE2RwojU0JBVENIIC0tbnRhc2tzPTggXG4iKQogICAgY2F0KHBhc3RlMCgiI1NCQVRDSCAtLWVycm9yIGFkbWl4VC4iLGksIi5lcnJcbiIpKQogICAgY2F0KCIjU0JBVENIIC0tdGltZT0zMDA6MDA6MDAKI1NCQVRDSCAtLW1haWwtdXNlcj1rdGlzdEB1Y2RhdmlzLmVkdSAjI2VtYWlsIHlvdSB3aGVuIGpvYiBzdGFydHMsZW5kcyxldGMKI1NCQVRDSCAtLW1haWwtdHlwZT1BTEwKI1NCQVRDSCAtcCBoaWdoIFxuIikKICAgIGNhdCgiXG4iKQogICAgY2F0KCJtb2R1bGUgbG9hZCBhbmdzZFxuXG4iKQogICAgCiAgICBmb3IgKGogaW4gMTo1KXsKICAgICAgICBjYXQocGFzdGUwKCJOR1NhZG1peCAtbGlrZXMgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9iZWFnbGUvVEJvbmx5X3BydW5lZF9tYWYwNV9CRUFHTEUuUEwuZ3ogLUsgIixpLCIgLW8gL2hvbWUva3Rpc3QvcGgvZGF0YS9OR1NhZG1peC9UQm9ubHlfcHJ1bmVkX21hZjA1X2siLGksIl9ydW4iLGosIiBcbiIpKQogICAgfQogICAgc2luayhOVUxMKQp9CmBgYAoKKiBDb21waWxlIGFsbCBsaWtlbGlob29kIG51bWJlcnMgZnJvbSBsb2cgZmlsZXMgaW50byAxIChsb2dmaWxlKSAgCmBgYHtiYXNoIGV2YWw9RkFMU0V9CiNsaW51eCBjb2RlICh3b24ndCB3b3JrIGZvciB1bml4KQooZm9yIGxvZyBpbiBgbHMgKi5sb2dgOyBkbyBncmVwIC1vUCAnbGlrZT1cS1teIF0rJyAkbG9nOyBkb25lKSA+IGxvZ2ZpbGVfazMKYGBgCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpzaW5rKHBhc3RlMCgiLi4vRGF0YS9TbHVybXNjcmlwdHMvbG9nZmlsZXNQLnNoIikpCmNhdCgiIyEvYmluL2Jhc2ggLWxcblxuIikKY2F0KHBhc3RlMCgiI1NCQVRDSCAtLWpvYi1uYW1lPWxvZ1AgXG4iKSkKY2F0KCIjU0JBVENIIC0tbWVtPTE2RwojU0JBVENIIC0tbnRhc2tzPTggXG4iKQpjYXQocGFzdGUwKCIjU0JBVENIIC0tZXJyb3IgbG9nUC5lcnJcbiIpKQpjYXQoIiNTQkFUQ0ggLS10aW1lPTI0OjAwOjAwCiNTQkFUQ0ggLXAgaGlnaCBcbiIpCmNhdCgiXG4iKQpmb3IgKGsgaW4gMjo2KXsKICAgIGNhdChwYXN0ZTAoImNkIC9ob21lL2t0aXN0L3BoL2RhdGEvTkdTYWRtaXgvUFdTX2siLGssIi8gXG4iKSkKICAgIGNhdCgiKGZvciBsb2cgaW4gYGxzICoubG9nYDsgZG8gZ3JlcCAtb1AgJ2xpa2U9XFxLW14gXSsnICRsb2c7IGRvbmUpID4gbG9nZmlsZV9rIikKICAgIGNhdChwYXN0ZTAoayAsIiBcbiIpKQp9CnNpbmsoTlVMTCkKYGBgCgoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbG9nMjwtcmVhZC50YWJsZSgiLi4vRGF0YS9uZ3NhZG1peC9UQi90Yl9sb2dfazIiLCBzZXA9Ilx0IiwgaGVhZGVyID1GQUxTRSkKbG9nMzwtcmVhZC50YWJsZSgiLi4vRGF0YS9uZ3NhZG1peC9UQi90Yl9sb2dfazMiLCBzZXA9Ilx0IiwgaGVhZGVyID1GQUxTRSkKbG9nNDwtcmVhZC50YWJsZSgiLi4vRGF0YS9uZ3NhZG1peC9UQi90Yl9sb2dfazQiLCBzZXA9Ilx0IiwgaGVhZGVyID1GQUxTRSkKbG9nNTwtcmVhZC50YWJsZSgiLi4vRGF0YS9uZ3NhZG1peC9UQi90Yl9sb2dfazUiLCBzZXA9Ilx0IiwgaGVhZGVyID1GQUxTRSkKbG9nNjwtcmVhZC50YWJsZSgiLi4vRGF0YS9uZ3NhZG1peC9UQi90Yl9sb2dfazYiLCBzZXA9Ilx0IiwgaGVhZGVyID1GQUxTRSkKCiNsb2dzPC1kYXRhLmZyYW1lKEs9YyhyZXAoMiwgdGltZXM9NSkscmVwKDMsIHRpbWVzPTUpLCByZXAoNCwgdGltZXM9NSkscmVwKDUsIHRpbWVzPTUpKSwgTGlrbGlob29kPWMobG9nazJbMTo1XSxsb2drM1sxOjVdLCBsb2drNCwgbG9nazUpKQoKbG9nczwtZGF0YS5mcmFtZShLPWMocmVwKDIsIHRpbWVzPTMpLHJlcCgzLCB0aW1lcz0zKSwgcmVwKDQsIHRpbWVzPTMpLHJlcCg1LCB0aW1lcz0zKSxyZXAoNiwgdGltZXM9MykpLCBMaWtsaWhvb2Q9Yyhsb2cyJFYxWzE6M10sbG9nMyRWMVsxOjNdLCBsb2c0JFYxWzE6M10sIGxvZzUkVjEsbG9nNiRWMSkpCndyaXRlLnRhYmxlKGxvZ3MsICIuLi9PdXRwdXQvbmdzYWRtaXgvVEJvbmx5X2xvZ3MudHh0Iiwgc2VwPSJcdCIsIHJvdy5uYW1lcyA9IEYsIGNvbC5uYW1lcyA9IEYsIHF1b3RlPUYpCgojIERPIE5PVCB1c2Ugc3BlY2lhbCBjaGFyYWN0ZXIgaW4gdGhlIGZpbGUgbmFtZQojTXVzdCBoYXZlIGF0IGxlYXN0IHRocmVlIEsgdmFsdWVzCgpgYGAKKiBrPTMgaXMgYmVzdCBieSBFdmFubm8gCgoKIyMjIEZTVHJ1Y3QgZm9yIFRCIG9ubHkKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcG9wX2luZm88LXJlYWQuY3N2KCIuLi9EYXRhL1NhbXBsZV9tZXRhZGF0YV84OTJwb3BzLmNzdiIpCnRiPC1jKCJUQjkxIiwiVEI5NiIsIlRCMDYiLCJUQjE3IikKcG9wX2luZm9UPC1wb3BfaW5mb1twb3BfaW5mbyRwb3A9PSJUQiIsXQoKcW1hdDwtcmVhZC50YWJsZShwYXN0ZTAoIi4uL0RhdGEvbmdzYWRtaXgvVEIvVEJvbmx5X3BydW5lZF9tYWYwNV9rMy5xb3B0IiksIGhlYWRlciA9IEYpCnFtYXQ8LWNiaW5kKHBvcF9pbmZvVFssYygiU2FtcGxlIiwiUG9wdWxhdGlvbi5ZZWFyIildLCBxbWF0KQpjb2xuYW1lcyhxbWF0KVsxOjJdPC1jKCJpbmQiLCJwb3AiKQpxbWF0JHBvcDwtZmFjdG9yKHFtYXQkcG9wLCBsZXZlbHM9dGIpCnFtYXQ8LXFtYXRbb3JkZXIocW1hdCRwb3ApLF0KCmttZWFuczwtYXBwbHkoYXMubWF0cml4KHFtYXRbcW1hdCRwb3A9PXRiWzFdLDM6NV0pLDIsbWVhbikKa19vcmRlcjwtbmFtZXMoa21lYW5zW29yZGVyKGttZWFucywgZGVjcmVhc2luZyA9IFQpXSkKcW1hdDwtcW1hdFssYygiaW5kIiwicG9wIixrX29yZGVyKV0KcW1hdF9zb3J0ZWQ8LWRhdGEuZnJhbWUoKQpmb3IgKGkgaW4gMTpsZW5ndGgodGIpKXsKICAgIGRmPC1xbWF0W3FtYXQkcG9wPT10YltpXSxdCiAgICBkZjwtZGZbb3JkZXIoZGZbLGNvbG5hbWVzKGRmKVtjb2xuYW1lcyhkZik9PWtfb3JkZXJbMV1dXSxkZlssY29sbmFtZXMoZGYpW2NvbG5hbWVzKGRmKT09a19vcmRlclszXV1dLGRlY3JlYXNpbmcgPSBjKFRSVUUsRkFMU0UpLCBtZXRob2Q9InJhZGl4IiksXQogICAgcW1hdF9zb3J0ZWQ8LXJiaW5kKHFtYXRfc29ydGVkLCBkZikKfQogICAgCm5pbmQ8LWRhdGEuZnJhbWUocG9wPXRiKQpuaW5kJG5bMV08LW5yb3cocW1hdFtxbWF0JHBvcD09dGJbMV0sXSkKbmluZCRtaWRbMV08LW5pbmQkblsxXS8yCmZvcihpIGluIDI6bGVuZ3RoKHRiKSl7CiAgICBubzwtbnJvdyhxbWF0W3FtYXQkcG9wPT10YltpXSxdKQogICAgbmluZCRuW2ldPC1uaW5kJG5baS0xXStubwogICAgbmluZCRtaWRbaV08LW5pbmQkbltpLTFdK25vLzIKfQoKcW08LXFtYXRfc29ydGVkWywyOjRdClFfcGxvdChRID0gcW1hdF9zb3J0ZWQsSz0zKSsKICAgICAgICAgICAgZ2dwbG90Mjo6c2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWNvbHMzKSsKICAgICAgICAgICAgZ2dwbG90Mjo6c2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jb2xzMykrCiAgICAgICAgICAgIGdncGxvdDI6OnNjYWxlX3hfY29udGludW91cyhsYWJlbHM9dGIsIGJyZWFrcz1uaW5kJG1pZCkrCiAgICAgICAgICAgIHRoZW1lX21pbmltYWwoKSt4bGFiKCcnKSt5bGFiKCcnKSsKICAgICAgICAgICAgdGhlbWUocGFuZWwuZ3JpZD1lbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT04KSkrCiAgICAgICAgICAgIGdncGxvdDI6OmFubm90YXRlKCdzZWdtZW50JywgeD1uaW5kJG5bMTozXSswLjUseT1yZXAoMCwgdGltZXM9MykseWVuZD1yZXAoMSwgdGltZXM9MyksIHhlbmQ9bmluZCRuWzE6M10rMC41LCAgICAgY29sb3I9ImdyYXkzMCIsIHNpemU9MC4zKQpnZ3NhdmUocGFzdGUwKCcuLi9PdXRwdXQvbmdzYWRtaXgvVEJvbmx5X3Bsb3RfT3B0aW1hbC5LMy5wbmcnKSwgd2lkdGggPSA4LjIsIGhlaWdodCA9IDMuNSwgZHBpPTMwMCkKICAgICAgIAojY2FsY3VsYXRlIHN0YXRzCiAgICBRczwtbGlzdCgpICNRbWF0cml4CiAgICBmb3IgKGkgaW4gMTogbGVuZ3RoKHRiKSl7CiAgICAgICAgZGY8LXFtYXRbcW1hdCRwb3A9PXRiW2ldLF0KICAgICAgICBRc1tbaV1dPC1kZgogICAgICAgIG5hbWVzKFFzKVtpXTwtdGJbaV0KICAgIH0gICAgICAgIAoKYm9vdHN0cmFwIDwtIFFfYm9vdHN0cmFwKG1hdHJpY2VzID0gUXMsbl9yZXBsaWNhdGVzID0gMTAwLEsgPSAzLHNlZWQgPSAxKQpjb3dwbG90OjpwbG90X2dyaWQoYm9vdHN0cmFwJHBsb3RfYm94cGxvdCArIGdncGxvdDI6OmdndGl0bGUoIkJveCBQbG90IikrZ2dwbG90Mjo6c2NhbGVfeF9kaXNjcmV0ZShsYWJlbHM9dGIpLCAKICAgICAgICAgICAgICAgICAgICAgICBib290c3RyYXAkcGxvdF92aW9saW4gKyBnZ3Bsb3QyOjpnZ3RpdGxlKCJWaW9saW4gUGxvdCIpK2dncGxvdDI6OnNjYWxlX3hfZGlzY3JldGUobGFiZWxzPXRiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgYm9vdHN0cmFwJHBsb3RfZWNkZiArIGdncGxvdDI6OmdndGl0bGUoIkVDREYgUGxvdCIpICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2dwbG90Mjo6c2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiRGFyazIiLCBsYWJlbHM9dGIpLCBucm93PTIpCmdnc2F2ZShwYXN0ZTAoIi4uL091dHB1dC9uZ3NhZG1peC9UQm9ubHlfZnN0cnVjdF9zdGF0c19PUFRJQU1MLmszLnBuZyIpLCB3aWR0aD0xMCwgaGVpZ2h0PTcsIGRwaT0zMDApCgpib290c3RyYXAkdGVzdF9wYWlyd2lzZV93aWxjb3gKIyAgICAgVEI5MSAgIFRCOTYgICBUQjA2ICAKI1RCOTYgMWUtMDYgIC0gICAgICAtICAgICAKI1RCMDYgPDJlLTE2IDwyZS0xNiAtICAgICAKI1RCMTcgPDJlLTE2IDwyZS0xNiA8MmUtMTYKCmBgYAohW10oLi4vT3V0cHV0L25nc2FkbWl4L1RCb25seV9wbG90X09wdGltYWwuSzMucG5nKSAgCgohW10oLi4vT3V0cHV0L25nc2FkbWl4L1RCb25seV9mc3RydWN0X3N0YXRzX09QVElBTUwuazMucG5nKQoKCgoKIyMgUnVuIE5HU2FkbWl4IGZvciBTUwoKYGBge2Jhc2ggZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KI2ZpcnN0IGNyZWF0ZSBwZWQvYmVkIGZpbGVzIHdpdGggYWRkaW5nIHZhcmlhbnQgaWQKbW9kdWxlIGxvYWQgcGxpbmsKcGxpbmsgLS12Y2YgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9TU29ubHlfTlMwLjVfbWFmMDUudmNmLmd6IC0tc2V0LW1pc3NpbmctdmFyLWlkcyBAOiNbcGhdXFwkcixcXCRhIC0tbWFrZS1iZWQgLS1vdXQgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9wbGlua2ZpbGVzL1NTb25seV9OUzAuNV9tYWYwNQoKcGxpbmsgLS1iZmlsZSAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL3BsaW5rZmlsZXMvU1Nvbmx5X05TMC41X21hZjA1IC0tcmVjb2RlIC0tdGFiIC0tb3V0IC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvcGxpbmtmaWxlcy9TU29ubHlfTlMwLjVfbWFmMDUKCiNmaW5kIGhpZ2hseSBjb3JyZWxhdGVkIHNpdGVzIGZvciBwcnVuaW5nCnBsaW5rIC0tZmlsZSAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL3BsaW5rZmlsZXMvU1Nvbmx5X05TMC41X21hZjA1IC0taW5kZXAtcGFpcndpc2UgNTAna2InIDUgMC41IC0tb3V0IC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvcGxpbmtmaWxlcy9TU29ubHlfTlMwLjVfbWFmMDVfNTBfNV8wLjUKCiNSZWZvcm1hdCBwcnVuLmluIGZpbGUgd2l0aCBydW5uaW5nIHRoZSByZWZvcm1hdF9wcnVuaW4uUgpSCnNvdXJjZSgicmVmb3JtYXRfcHJ1bmluLlIiKQpyZWZvcm1hdF9wcnVuaW4oInBoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvcGxpbmtmaWxlcy9TU29ubHlfTlMwLjVfbWFmMDVfNTBfNV8wLjUucHJ1bmUuaW4iKQpxdWl0KCkKCiMjIFVzZSBiY2Z0b29scyB0byBzdWJzZXQgdGhlIFZDRiBmaWxlIHdpdGggLnBydW5lLmluLnNpdGVzLnR4dApiY2Z0b29scyBpbmRleCAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL1NTb25seV9OUzAuNV9tYWYwNS52Y2YuZ3ogCgpiY2Z0b29scyB2aWV3IC1SIC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvcGxpbmtmaWxlcy9TU29ubHlfTlMwLjVfbWFmMDVfNTBfNV8wLjUucHJ1bmUuaW4uc2l0ZXMudHh0ICAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL1NTb25seV9OUzAuNV9tYWYwNS52Y2YuZ3ogPiAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL3BydW5lZC9TU29ubHlfTlMwLjVfbWFmMDVfcHJ1bmVkLnZjZgoKYmd6aXAgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9wcnVuZWQvU1Nvbmx5X05TMC41X21hZjA1X3BydW5lZC52Y2YKYGBgCgpgYGB7ciBldmFsPUZBTFNFfQojIyBDcmVhdGUgYmVhZ2xlIGZpbGVzCnNpbmsocGFzdGUwKCIuLi9EYXRhL1NsdXJtc2NyaXB0cy9iZWFnbGVfc3Muc2giKSkKY2F0KCIjIS9iaW4vYmFzaCAtbFxuXG4iKQpjYXQocGFzdGUwKCIjU0JBVENIIC0tam9iLW5hbWU9YmVhZ2xlIFxuIikpCmNhdChwYXN0ZTAoIiNTQkFUQ0ggLS1tZW09MTZHIFxuIikpIApjYXQocGFzdGUwKCIjU0JBVENIIC0tbnRhc2tzPTggXG4iKSkKY2F0KHBhc3RlMCgiI1NCQVRDSCAtZSBiZWFnbGUuZXJyICBcbiIpKQpjYXQocGFzdGUwKCIjU0JBVENIIC0tdGltZT03MjowMDowMCAgXG4iKSkKY2F0KHBhc3RlMCgiI1NCQVRDSCAtcCBoaWdoICBcbiIpKQpjYXQoIlxuIikKZm9yIChpIGluIDE6MjYpewogICBjYXQocGFzdGUwKCJ2Y2Z0b29scyAtLWd6dmNmIC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvcHJ1bmVkL1NTb25seV9OUzAuNV9tYWYwNV9wcnVuZWQudmNmLmd6IC0tY2hyIGNocjEgLS1vdXQgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9iZWFnbGUvU1Nvbmx5X3BydW5lZF9jIixpLCIgLS1CRUFHTEUtUEwgXG4iKSkKfQpjYXQoIlxuIikKZm9yIChpIGluIDI6MjYpewogICAgY2F0KHBhc3RlMCgic2VkIC1lICcxLCAxZCcgPCAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL2JlYWdsZS9TU29ubHlfcHJ1bmVkX2MiLGksIi5CRUFHTEUuUEwgPiAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL2JlYWdsZS9TU29ubHlfcHJ1bmVkX2MiLGksIi4yLkJFQUdMRS5QTCBcbiIpKQp9CmNhdCgiXG4iKQoKY2F0KCJjYXQgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9iZWFnbGUvU1Nvbmx5X3BydW5lZF9jMS5CRUFHTEUuUEwgIikgCmZvciAoaSBpbiAyOjI2KXsKICAgIGNhdChwYXN0ZTAoIi9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvYmVhZ2xlL1NTb25seV9wcnVuZWRfYyIsaSwiLjIuQkVBR0xFLlBMICIpKQp9CmNhdChwYXN0ZTAoIiA+IC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvYmVhZ2xlL1NTb25seV9wcnVuZWRfbWFmMDVfQkVBR0xFLlBMIFxuIikpCmNhdCgiZ3ppcCAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL2JlYWdsZS9TU29ubHlfcHJ1bmVkX21hZjA1X0JFQUdMRS5QTCBcblxuIikKCnNpbmsoTlVMTCkKCiNmaXJzdCBydW4gb25jZToKZm9yIChpIGluIDI6NikgewogICAgc2luayhwYXN0ZTAoIi4uL0RhdGEvU2x1cm1zY3JpcHRzL1J1bk5HU2FkbWl4UyIsaSwiLnNoIikpCiAgICBjYXQoIiMhL2Jpbi9iYXNoIC1sXG5cbiIpCiAgICBjYXQocGFzdGUwKCIjU0JBVENIIC0tam9iLW5hbWU9YWRtaXhTIixpLCJcbiIpKQogICAgY2F0KCIjU0JBVENIIC0tbWVtPTE2RwojU0JBVENIIC0tbnRhc2tzPTggXG4iKQogICAgY2F0KHBhc3RlMCgiI1NCQVRDSCAtLWVycm9yIGFkbWl4UyIsaSwiLmVyclxuIikpCiAgICBjYXQoIiNTQkFUQ0ggLS10aW1lPTQ4OjAwOjAwCiNTQkFUQ0ggLS1tYWlsLXVzZXI9a3Rpc3RAdWNkYXZpcy5lZHUgIyNlbWFpbCB5b3Ugd2hlbiBqb2Igc3RhcnRzLGVuZHMsZXRjCiNTQkFUQ0ggLS1tYWlsLXR5cGU9QUxMCiNTQkFUQ0ggLXAgaGlnaCBcbiIpCiAgICBjYXQoIlxuIikKICAgIGNhdCgibW9kdWxlIGxvYWQgYW5nc2RcblxuIikKICAgIAogICAgY2F0KHBhc3RlMCgiTkdTYWRtaXggLWxpa2VzIC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvYmVhZ2xlL1NTb25seV9wcnVuZWRfbWFmMDVfQkVBR0xFLlBMLmd6IC1LICIsaSwiIC1vIC9ob21lL2t0aXN0L3BoL2RhdGEvTkdTYWRtaXgvU1Nvbmx5X3BydW5lZF9tYWYwNV9rIixpLCIgXG4iKSkKICAgIHNpbmsoTlVMTCkKfQoKCgpgYGAKCiMjIFJ1biBldmFsQWRtaXggZm9yIFNTIChsb2NhbGx5KQpgYGB7ciBldmFsPUZBTFNFfQpzaW5rKHBhc3RlMCgiLi4vRGF0YS9TbHVybXNjcmlwdHMvZXZhbEFkbWl4X3J1bmxvY2FsX3NzLnNoIikpCmNhdCgiIyEvYmluL2Jhc2ggXG5cbiIpCmZvciAoaSBpbiAyOjYpewogICAgY2F0KHBhc3RlMCgiZXZhbEFkbWl4IC1iZWFnbGUgRGF0YS9uZ3NhZG1peC9TUy9TU29ubHlfcHJ1bmVkX21hZjA1X0JFQUdMRS5QTC5neiAtZm5hbWUgRGF0YS9uZ3NhZG1peC9TUy9TU29ubHlfcHJ1bmVkX21hZjA1X2siLGksIi5mb3B0Lmd6IC1xbmFtZSBEYXRhL25nc2FkbWl4L1NTL1NTb25seV9wcnVuZWRfbWFmMDVfayIsaSwiLnFvcHQgLVAgOCAtbyBTU29ubHlfb3V0cHV0LmNvcnJlcy5rIixpLCIudHh0IFxuIikpCn0Kc2luayhOVUxMKQpgYGAKCiMjIE5HU2FkbWl4IGFuZCBFdmFsQWRtaXggb3V0cHV0cyBmb3IgU1MKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KI091dHB1dCBmaWxlcwpxZmlsZXM8LWxpc3QuZmlsZXMoIi4uL0RhdGEvbmdzYWRtaXgvU1MvIixwYXR0ZXJuPSJeU1Nvbmx5LisucW9wdCIpCm9maWxlczwtbGlzdC5maWxlcygiLi4vRGF0YS9uZ3NhZG1peC9TUy8iLHBhdHRlcm49Il5TU29ubHkuK291dHB1dC5jb3JyZXMiKQoKI3BvcHVsYXRpb24gaW5mbwpwb3A8LXJlYWQuY3N2KCIuLi9EYXRhL1NhbXBsZV9tZXRhZGF0YV84OTJwb3BzLmNzdiIpCnNwb3A8LXBvcFtncmVwbCgiU1MiLHBvcCRTYW1wbGUpLF0Kc3BvcCRQb3B1bGF0aW9uLlllYXI8LWZhY3RvcihzcG9wJFBvcHVsYXRpb24uWWVhciwgbGV2ZWxzPWMoIlNTOTYiLCJTUzA2IiwiU1MxNyIpKQpzcG9wb3JkZXI8LXBhc3RlKHNwb3AkUG9wdWxhdGlvbi5ZZWFyW29yZGVyKHNwb3AkUG9wdWxhdGlvbi5ZZWFyKV0pCnNwb3Bfb3JkZXI8LWMoIlNTOTYiLCJTUzA2IiwiU1MxNyIpCgpmb3IgKGkgaW4gMTpsZW5ndGgocWZpbGVzKSl7CiAgICAjIGV4dHJhY3QgSyBmcm9tIHRoZSBmaWxlIG5hbWUKICAgIG9uYW1lPC1xZmlsZXNbaV0KICAgIGs8LWFzLmludGVnZXIoc3RyX2V4dHJhY3Qob25hbWUsICJbWzpkaWdpdDpdXSsiKSkKICAgIAogICAgI3JlYWQgdGhlIHFvcHQgZmlsZSBmb3Igaz1rCiAgICBxPC1yZWFkLnRhYmxlKHBhc3RlMCgiLi4vRGF0YS9uZ3NhZG1peC9TUy8iLCBxZmlsZXNbaV0pKQogICAgCiAgICAjb3JkZXIgYWNjb3JkaW5nIHRvIHBvcHVsYXRpb24gYW5kIHBsb3QgdGhlIE5HU2FkbWl4IHJlc3VsdHMKICAgIHEkaWQ8LXNwb3AkUG9wdWxhdGlvbi5ZZWFyCiAgICBxPC1xW29yZGVyKHEkaWQpLF0KICAgIAogICAgb3JkPC1vcmRlckluZHMocG9wID0gYXMudmVjdG9yKHNwb3BvcmRlciksIHEgPSBxWywxOihpKzEpXSkKICAgIAogICAgeGxhYmVsczwtZGF0YS5mcmFtZSh4PXRhcHBseSgxOmxlbmd0aChzcG9wb3JkZXIpLGxpc3Qoc3BvcG9yZGVyKSwgbWVhbikpCiAgICB4bGFiZWxzJHBvcDwtZmFjdG9yKHJvd25hbWVzKHhsYWJlbHMpLCBsZXZlbHM9c3BvcF9vcmRlcikKICAgIHhsYWJlbHM8LXhsYWJlbHNbb3JkZXIoeGxhYmVscyRwb3ApLF0KICAgIAogICAgaWYgKGk9PTF8aT09MikgY29sb3JzPWMoMiw0LDcpCiAgICBpZiAoaT09MykgY29sb3JzPWMoNSwyLDcsNCwzKSAKICAgIGlmIChpPT00fGk9PTUpIGNvbG9ycz1jKDQsMiw1LDcsMykKCiAgICB7cG5nKHBhc3RlMCgiLi4vT3V0cHV0L25nc2FkbWl4L1NTb25seV9BZG1peF9wbG90X2siLGssIi5wbmciKSwgaGVpZ2h0ID0gMy41LCB3aWR0aD02LCB1bml0PSJpbiIsIHJlcz0zMDApCiAgICBiYXJwbG90KHQocVssMTooaSsyKV0pWyxvcmRdLGNvbD1jb2xvcnMsc3BhY2U9MCxib3JkZXI9TkEseGF4dD0ibiIseGxhYj0iUG9wdWxhdGlvbiIseWxhYj1wYXN0ZTAoIkFkbWl4dHVyZSBwcm9wb3J0aW9ucyBmb3IgSz0iLGspKQogICAgdGV4dCh4bGFiZWxzJHgsLTAuMDUseGxhYmVscyRwb3AseHBkPVQsIHNydD05MCwgYWRqPTEsY2V4PTAuOCkKICAgIGFibGluZSh2PWN1bXN1bShzYXBwbHkodW5pcXVlKHNwb3BvcmRlcltvcmRdKSxmdW5jdGlvbih4KXtzdW0oc3BvcFtvcmQsIlBvcHVsYXRpb24uWWVhciJdPT14KX0pKSxjb2w9MSxsd2Q9MS4yKQogICAgZGV2Lm9mZigpfQogICAgCiAgICAjUGxvdCB0aGUgY29ycmVsYXRpb24gbWF0cml4IGZyb20gZXZhbEFkbWl4CiAgICByPC1yZWFkLnRhYmxlKHBhc3RlMCgiLi4vRGF0YS9uZ3NhZG1peC9TUy8iLG9maWxlc1tpXSkpCiAgICAKICAgICMgUGxvdCBjb3JyZWxhdGlvbiBvZiByZXNpZHVhbHMKICAgIHtwZGYocGFzdGUwKCIuLi9PdXRwdXQvbmdzYWRtaXgvU1Nvbmx5X2V2YWxBZG1peF9jb3JwbG90X2siLGssIi5wZGYiKSwgaGVpZ2h0ID0gNiwgd2lkdGg9OCkKICAgIHBsb3RDb3JSZXMoY29yX21hdCA9IHIsIHBvcCA9IGFzLnZlY3RvcihzcG9wWywiUG9wdWxhdGlvbi5ZZWFyIl0pLCBvcmQgPSBvcmQsIHRpdGxlPXBhc3RlMCgiRXZhbHVhdGlvbiBvZiBhZG1peHR1cmUgcHJvcG9ydGlvbnMgd2l0aCBLPSIsayksIG1heF96PTAuMSwgbWluX3o9LTAuMSkKICAgIGRldi5vZmYoKX0KfQoKYGBgCiFbXSguLi9PdXRwdXQvbmdzYWRtaXgvU1Nvbmx5X0FkbWl4X3Bsb3RfazIucG5nKSAgCiFbXSguLi9PdXRwdXQvbmdzYWRtaXgvU1Nvbmx5X0FkbWl4X3Bsb3RfazMucG5nKSAgCgojIyMgUnVuIGVhY2ggayBmb3IgNSB0aW1lcyB0byBhc3Nlc3MgdGhlIGJlc3QgayAgKFNTKQpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojY3JlYXRlIHNsdXJtIHNjcmlwdHMgdG8gcnVuIE5HU2FkbWl4IHggMTAKZm9yIChpIGluIDI6NSkgewogICAgc2luayhwYXN0ZTAoIi4uL0RhdGEvU2x1cm1zY3JpcHRzL05HU2FkbWl4Uy4iLGksIi5zaCIpKQogICAgY2F0KCIjIS9iaW4vYmFzaCAtbFxuXG4iKQogICAgY2F0KHBhc3RlMCgiI1NCQVRDSCAtLWpvYi1uYW1lPWFkbWl4Uy4iLGksIlxuIikpCiAgICBjYXQoIiNTQkFUQ0ggLS1tZW09MTZHCiNTQkFUQ0ggLS1udGFza3M9OCBcbiIpCiAgICBjYXQocGFzdGUwKCIjU0JBVENIIC0tZXJyb3IgYWRtaXhTLiIsaSwiLmVyclxuIikpCiAgICBjYXQoIiNTQkFUQ0ggLS10aW1lPTMwMDowMDowMAojU0JBVENIIC0tbWFpbC11c2VyPWt0aXN0QHVjZGF2aXMuZWR1ICMjZW1haWwgeW91IHdoZW4gam9iIHN0YXJ0cyxlbmRzLGV0YwojU0JBVENIIC0tbWFpbC10eXBlPUFMTAojU0JBVENIIC1wIGhpZ2ggXG4iKQogICAgY2F0KCJcbiIpCiAgICBjYXQoIm1vZHVsZSBsb2FkIGFuZ3NkXG5cbiIpCiAgICAKICAgIGZvciAoaiBpbiAxOjUpewogICAgICAgIGNhdChwYXN0ZTAoIk5HU2FkbWl4IC1saWtlcyAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL2JlYWdsZS9UQm9ubHlfcHJ1bmVkX21hZjA1X0JFQUdMRS5QTC5neiAtSyAiLGksIiAtbyAvaG9tZS9rdGlzdC9waC9kYXRhL05HU2FkbWl4L1NTb25seV9wcnVuZWRfbWFmMDVfayIsaSwiX3J1biIsaiwiIFxuIikpCiAgICB9CiAgICBzaW5rKE5VTEwpCn0KCmBgYAoKIyMjIEZTVHJ1Y3QgZm9yIFNTCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnBvcF9pbmZvPC1yZWFkLmNzdigiLi4vRGF0YS9TYW1wbGVfbWV0YWRhdGFfODkycG9wcy5jc3YiKQpzczwtYygiU1M5NiIsIlNTMDYiLCJTUzE3IikKcG9wX2luZm9TPC1wb3BfaW5mb1twb3BfaW5mbyRwb3A9PSJTUyIsXQoKcW1hdDwtcmVhZC50YWJsZShwYXN0ZTAoIi4uL0RhdGEvbmdzYWRtaXgvU1MvU1Nvbmx5X3BydW5lZF9tYWYwNV9rMy5xb3B0IiksIGhlYWRlciA9IEYpCnFtYXQ8LWNiaW5kKHBvcF9pbmZvU1ssYygiU2FtcGxlIiwiUG9wdWxhdGlvbi5ZZWFyIildLCBxbWF0KQpjb2xuYW1lcyhxbWF0KVsxOjJdPC1jKCJpbmQiLCJwb3AiKQpxbWF0JHBvcDwtZmFjdG9yKHFtYXQkcG9wLCBsZXZlbHM9c3MpCnFtYXQ8LXFtYXRbb3JkZXIocW1hdCRwb3ApLF0KCmttZWFuczwtYXBwbHkoYXMubWF0cml4KHFtYXRbcW1hdCRwb3A9PXNzWzFdLDM6NV0pLDIsbWVhbikKa19vcmRlcjwtbmFtZXMoa21lYW5zW29yZGVyKGttZWFucywgZGVjcmVhc2luZyA9IFQpXSkKcW1hdDwtcW1hdFssYygiaW5kIiwicG9wIixrX29yZGVyKV0KcW1hdF9zb3J0ZWQ8LWRhdGEuZnJhbWUoKQpmb3IgKGkgaW4gMTpsZW5ndGgoc3MpKXsKICAgIGRmPC1xbWF0W3FtYXQkcG9wPT1zc1tpXSxdCiAgICBkZjwtZGZbb3JkZXIoZGZbLGNvbG5hbWVzKGRmKVtjb2xuYW1lcyhkZik9PWtfb3JkZXJbMV1dXSxkZlssY29sbmFtZXMoZGYpW2NvbG5hbWVzKGRmKT09a19vcmRlclszXV1dLGRlY3JlYXNpbmcgPSBjKFRSVUUsRkFMU0UpLCBtZXRob2Q9InJhZGl4IiksXQogICAgcW1hdF9zb3J0ZWQ8LXJiaW5kKHFtYXRfc29ydGVkLCBkZikKfQogICAgCm5pbmQ8LWRhdGEuZnJhbWUocG9wPXNzKQpuaW5kJG5bMV08LW5yb3cocW1hdFtxbWF0JHBvcD09c3NbMV0sXSkKbmluZCRtaWRbMV08LW5pbmQkblsxXS8yCmZvcihpIGluIDI6bGVuZ3RoKHNzKSl7CiAgICBubzwtbnJvdyhxbWF0W3FtYXQkcG9wPT1zc1tpXSxdKQogICAgbmluZCRuW2ldPC1uaW5kJG5baS0xXStubwogICAgbmluZCRtaWRbaV08LW5pbmQkbltpLTFdK25vLzIKfQoKUV9wbG90KFEgPSBxbWF0X3NvcnRlZCxLPTMpKwogICAgICAgICAgICBnZ3Bsb3QyOjpzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9Y29sczMpKwogICAgICAgICAgICBnZ3Bsb3QyOjpzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWNvbHMzKSsKICAgICAgICAgICAgZ2dwbG90Mjo6c2NhbGVfeF9jb250aW51b3VzKGxhYmVscz1zcywgYnJlYWtzPW5pbmQkbWlkKSsKICAgICAgICAgICAgdGhlbWVfbWluaW1hbCgpK3hsYWIoJycpK3lsYWIoJycpKwogICAgICAgICAgICB0aGVtZShwYW5lbC5ncmlkPWVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTgpKSsKICAgICAgICAgICAgZ2dwbG90Mjo6YW5ub3RhdGUoJ3NlZ21lbnQnLCB4PW5pbmQkblsxOjNdKzAuNSx5PXJlcCgwLCB0aW1lcz0zKSx5ZW5kPXJlcCgxLCB0aW1lcz0zKSwgeGVuZD1uaW5kJG5bMTozXSswLjUsICAgICBjb2xvcj0iZ3JheTMwIiwgc2l6ZT0wLjMpCmdnc2F2ZShwYXN0ZTAoJy4uL091dHB1dC9uZ3NhZG1peC9TU29ubHlfcGxvdF9PcHRpbWFsLkszLnBuZycpLCB3aWR0aCA9IDguMiwgaGVpZ2h0ID0gMy41LCBkcGk9MzAwKQogICAgICAgCiNjYWxjdWxhdGUgc3RhdHMKUXM8LWxpc3QoKSAjUW1hdHJpeApmb3IgKGkgaW4gMTogbGVuZ3RoKHNzKSl7CiAgICBkZjwtcW1hdFtxbWF0JHBvcD09c3NbaV0sXQogICAgUXNbW2ldXTwtZGYKICAgIG5hbWVzKFFzKVtpXTwtc3NbaV0KfSAgICAgICAgCmJvb3RzdHJhcCA8LSBRX2Jvb3RzdHJhcChtYXRyaWNlcyA9IFFzLG5fcmVwbGljYXRlcyA9IDEwMCxLID0gMyxzZWVkID0gMSkKY293cGxvdDo6cGxvdF9ncmlkKGJvb3RzdHJhcCRwbG90X2JveHBsb3QgKyBnZ3Bsb3QyOjpnZ3RpdGxlKCJCb3ggUGxvdCIpK2dncGxvdDI6OnNjYWxlX3hfZGlzY3JldGUobGFiZWxzPXNzKSwgCiAgICAgICAgICAgICAgICAgICAgICAgYm9vdHN0cmFwJHBsb3RfdmlvbGluICsgZ2dwbG90Mjo6Z2d0aXRsZSgiVmlvbGluIFBsb3QiKStnZ3Bsb3QyOjpzY2FsZV94X2Rpc2NyZXRlKGxhYmVscz1zcyksIAogICAgICAgICAgICAgICAgICAgICAgIGJvb3RzdHJhcCRwbG90X2VjZGYgKyBnZ3Bsb3QyOjpnZ3RpdGxlKCJFQ0RGIFBsb3QiKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGdncGxvdDI6OnNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIiwgbGFiZWxzPXNzKSwgbnJvdz0yKQpnZ3NhdmUocGFzdGUwKCIuLi9PdXRwdXQvbmdzYWRtaXgvU1Nvbmx5X2ZzdHJ1Y3Rfc3RhdHNfT1BUSUFNTC5rMy5wbmciKSwgd2lkdGg9MTAsIGhlaWdodD03LCBkcGk9MzAwKQoKYm9vdHN0cmFwJHRlc3RfcGFpcndpc2Vfd2lsY294CiMgICAgIFNTOTYgICAgU1MwNiAgIAojU1MwNiA3LjVlLTA3IC0gICAgICAKI1NTMTcgMC4xNSAgICA4LjRlLTA5Cgpib290c3RyYXAkdGVzdF9rcnVza2FsX3dhbGxpcwojS3J1c2thbC1XYWxsaXMgY2hpLXNxdWFyZWQgPSA0Mi4xNzMsIGRmID0gMiwgcC12YWx1ZSA9IDYuOTU1ZS0xMAoKYGBgCiFbXSguLi9PdXRwdXQvbmdzYWRtaXgvU1Nvbmx5X3Bsb3RfT3B0aW1hbC5LMy5wbmcpICAKCiFbXSguLi9PdXRwdXQvbmdzYWRtaXgvU1Nvbmx5X2ZzdHJ1Y3Rfc3RhdHNfT1BUSUFNTC5rMy5wbmcpCgoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KYGBgCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpgYGAKCgoK